diff --git a/localstripe/resources.py b/localstripe/resources.py index b979671..aede6df 100644 --- a/localstripe/resources.py +++ b/localstripe/resources.py @@ -1229,6 +1229,7 @@ def __init__(self, customer=None, subscription=None, metadata=None, simulation=False, upcoming=False, tax_percent=None, # deprecated default_tax_rates=None, is_trial=False, + automatic_tax=None, ** kwargs): if kwargs: raise UserError(400, 'Unexpected ' + ', '.join(kwargs.keys())) @@ -1255,6 +1256,12 @@ def __init__(self, customer=None, subscription=None, metadata=None, assert type(default_tax_rates) is list assert all(type(txr) is str and txr.startswith('txr_') for txr in default_tax_rates) + if automatic_tax is not None: + assert ('enabled' in automatic_tax + and automatic_tax['enabled'] in + ("false", "true", True, False)) + enabled = try_convert_to_bool(automatic_tax['enabled']) + automatic_tax['enabled'] = enabled except AssertionError: raise UserError(400, 'Bad request') @@ -1298,6 +1305,7 @@ def __init__(self, customer=None, subscription=None, metadata=None, self.period_start = None self.period_end = None self.coupon = None + self.automatic_tax = automatic_tax if subscription is not None: self.period_start = subscription_obj.current_period_start self.period_end = subscription_obj.current_period_end @@ -1477,7 +1485,8 @@ def _get_next_invoice(cls, customer=None, subscription=None, subscription_tax_percent=None, # deprecated subscription_default_tax_rates=None, subscription_trial_end=None, - pending_invoice_items_behavior=None): + pending_invoice_items_behavior="exclude", + automatic_tax=None): subscription_proration_date = \ try_convert_to_int(subscription_proration_date) try: @@ -1505,6 +1514,14 @@ def _get_next_invoice(cls, customer=None, subscription=None, if subscription_proration_date is not None: assert type(subscription_proration_date) is int assert subscription_proration_date > 1500000000 + if automatic_tax is not None: + assert ('enabled' in automatic_tax + and automatic_tax['enabled'] in ("false", "true")) + enabled = try_convert_to_bool(automatic_tax['enabled']) + automatic_tax['enabled'] = enabled + assert (type(pending_invoice_items_behavior) is str + and pending_invoice_items_behavior in + ("exclude", "include")) except AssertionError: raise UserError(400, 'Bad request') @@ -1581,7 +1598,9 @@ def _get_next_invoice(cls, customer=None, subscription=None, if current_subscription: date = current_subscription.current_period_end - if not simulation and not current_subscription: + if (not simulation + and not current_subscription + and pending_invoice_items_behavior == "exclude"): raise UserError(404, 'No upcoming invoices for customer') elif not simulation and current_subscription: @@ -1592,8 +1611,17 @@ def _get_next_invoice(cls, customer=None, subscription=None, tax_percent=tax_percent, default_tax_rates=default_tax_rates, date=date, - description=description) - + description=description, + automatic_tax=automatic_tax) + elif not simulation and pending_invoice_items_behavior == "include": + return cls(upcoming=upcoming, + customer=customer, + items=invoice_items, + tax_percent=tax_percent, + default_tax_rates=default_tax_rates, + date=date, + description=description, + automatic_tax=automatic_tax) else: # if simulation if subscription is not None: # Get previous invoice for this subscription and customer, and @@ -1625,6 +1653,7 @@ def _get_next_invoice(cls, customer=None, subscription=None, default_tax_rates=default_tax_rates, date=date, description=description, + automatic_tax=automatic_tax, simulation=True) if subscription_proration_date is not None: @@ -1637,12 +1666,13 @@ def _get_next_invoice(cls, customer=None, subscription=None, @classmethod def _api_create(cls, customer=None, subscription=None, tax_percent=None, default_tax_rates=None, description=None, metadata=None, - pending_invoice_items_behavior=None): + pending_invoice_items_behavior=None, automatic_tax=None): return cls._get_next_invoice( customer=customer, subscription=subscription, tax_percent=tax_percent, default_tax_rates=default_tax_rates, description=description, metadata=metadata, - pending_invoice_items_behavior=pending_invoice_items_behavior) + pending_invoice_items_behavior=pending_invoice_items_behavior, + automatic_tax=automatic_tax) @classmethod def _api_delete(cls, id): @@ -1773,9 +1803,9 @@ class InvoiceItem(StripeObject): _id_prefix = 'ii_' def __init__(self, invoice=None, subscription=None, plan=None, amount=None, - currency=None, customer=None, period_start=None, + currency=None, customer=None, period_start=None, price=None, period_end=None, proration=False, description=None, - tax_rates=[], metadata=None, **kwargs): + tax_rates=[], metadata=None, quantity=None, **kwargs): if kwargs: raise UserError(400, 'Unexpected ' + ', '.join(kwargs.keys())) @@ -1783,6 +1813,7 @@ def __init__(self, invoice=None, subscription=None, plan=None, amount=None, period_start = try_convert_to_int(period_start) period_end = try_convert_to_int(period_end) proration = try_convert_to_bool(proration) + quantity = try_convert_to_int(quantity) try: if invoice is not None: assert type(invoice) is str and invoice.startswith('in_') @@ -1791,8 +1822,11 @@ def __init__(self, invoice=None, subscription=None, plan=None, amount=None, assert subscription.startswith('sub_') if plan is not None: assert type(plan) is str and plan - assert type(amount) is int - assert type(currency) is str and currency + if price is None: + assert type(amount) is int + assert type(currency) is str and currency + else: + assert type(price) is str assert type(customer) is str and customer.startswith('cus_') if period_start is not None: assert type(period_start) is int and period_start > 1500000000 @@ -1800,6 +1834,8 @@ def __init__(self, invoice=None, subscription=None, plan=None, amount=None, else: period_start = period_end = int(time.time()) assert type(proration) is bool + if quantity is not None: + assert type(quantity) is int and quantity > 0 if description is not None: assert type(description) is str else: @@ -1834,6 +1870,12 @@ def __init__(self, invoice=None, subscription=None, plan=None, amount=None, self.description = description self.tax_rates = tax_rates self.metadata = metadata or {} + self.quantity = quantity + self.price = price + if price is not None: + p = Price._api_retrieve(price) + self.currency = p.currency + self.amount = p.unit_amount @classmethod def _api_list_all(cls, url, customer=None, limit=None, @@ -2287,7 +2329,8 @@ def _requires_authentication(self): '4000008400001629') if self.token is not None: return self.token in ( - 'tok_visa_chargeDeclinedInsufficientFunds') + 'tok_visa_chargeDeclinedInsufficientFunds', + ) return False def _attaching_is_declined(self): diff --git a/test.sh b/test.sh index 1575b9c..c0935ee 100755 --- a/test.sh +++ b/test.sh @@ -990,4 +990,9 @@ charge=$(curl -sSfgG -u $SK: $HOST/v1/invoices \ curl -sSfg -u $SK: $HOST/v1/subscriptions \ -d customer=$cus \ -d items[0][plan]=basique-mensuel \ - -d automatic_tax[enabled]=true \ No newline at end of file + -d automatic_tax[enabled]=true + +curl -sSfg -u $SK: $HOST/v1/invoiceitems \ + -d customer=$cus \ + -d price=39999_usd_us \ + -d quantity=1 \ No newline at end of file