changeset a84c94e1d191 in modules/account_payment_stripe:default
details:
https://hg.tryton.org/modules/account_payment_stripe?cmd=changeset&node=a84c94e1d191
description:
Add wizard to create direct debit for configured parties
issue10772
review379071002
diffstat:
__init__.py | 1 +
common.py | 144 +++++++++++++++++++++++
party.py | 15 ++
party.xml | 12 +
payment.py | 176 ++++++----------------------
tryton.cfg | 1 +
view/party_reception_direct_debit_form.xml | 18 ++
7 files changed, 233 insertions(+), 134 deletions(-)
diffs (466 lines):
diff -r 92d7812129fc -r a84c94e1d191 __init__.py
--- a/__init__.py Mon Oct 11 18:22:19 2021 +0200
+++ b/__init__.py Mon Oct 11 18:35:28 2021 +0200
@@ -21,6 +21,7 @@
payment.Payment,
payment.CustomerSourceDetachAsk,
party.Party,
+ party.PartyReceptionDirectDebit,
ir.Cron,
module='account_payment_stripe', type_='model')
Pool.register(
diff -r 92d7812129fc -r a84c94e1d191 common.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/common.py Mon Oct 11 18:35:28 2021 +0200
@@ -0,0 +1,144 @@
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+from trytond.model import fields
+from trytond.pyson import Eval
+
+
+class StripeCustomerMethodMixin:
+ __slots__ = ()
+
+ stripe_account = fields.Function(fields.Many2One(
+ 'account.payment.stripe.account', "Stripe Account"),
+ 'on_change_with_stripe_account')
+
+ stripe_customer = fields.Many2One(
+ 'account.payment.stripe.customer', "Stripe Customer",
+ domain=[
+ ('party', '=', Eval('party', -1)),
+ ('stripe_account', '=', Eval('stripe_account', -1)),
+ ],
+ states={
+ 'invisible': Eval('process_method') != 'stripe',
+ 'readonly': (
+ ~Eval('party') | (Eval('party', -1) < 0)
+ | ~Eval('stripe_account') | (Eval('stripe_account', -1) < 0)),
+ },
+ depends=['party', 'stripe_account', 'process_method'])
+
+ stripe_customer_source = fields.Char(
+ "Stripe Customer Source",
+ states={
+ 'invisible': (
+ (Eval('process_method') != 'stripe')
+ | ~Eval('stripe_customer')
+ | Eval('stripe_customer_payment_method')),
+ },
+ depends=[
+ 'process_method', 'stripe_customer',
+ 'stripe_customer_payment_method'])
+ # Use Function field with selection to avoid to query Stripe
+ # to validate the value
+ stripe_customer_source_selection = fields.Function(fields.Selection(
+ 'get_stripe_customer_sources', "Stripe Customer Source",
+ states={
+ 'invisible': (
+ (Eval('process_method') != 'stripe')
+ | ~Eval('stripe_customer')
+ | Eval('stripe_customer_payment_method')),
+ },
+ depends=[
+ 'process_method', 'stripe_customer',
+ 'stripe_customer_payment_method']),
+ 'get_stripe_customer_source', setter='set_stripe_customer_source')
+
+ stripe_customer_payment_method = fields.Char(
+ "Stripe Payment Method",
+ states={
+ 'invisible': (
+ (Eval('process_method') != 'stripe')
+ | ~Eval('stripe_customer')
+ | Eval('stripe_customer_source')),
+ },
+ depends=[
+ 'process_method', 'stripe_customer', 'stripe_customer_source'])
+ # Use Function field with selection to avoid to query Stripe
+ # to validate the value
+ stripe_customer_payment_method_selection = fields.Function(
+ fields.Selection(
+ 'get_stripe_customer_payment_methods',
+ "Stripe Customer Payment Method",
+ states={
+ 'invisible': (
+ (Eval('process_method') != 'stripe')
+ | ~Eval('stripe_customer')
+ | Eval('stripe_customer_source')),
+ },
+ depends=[
+ 'process_method', 'stripe_customer',
+ 'stripe_customer_source']),
+ 'get_stripe_customer_payment_method',
+ setter='set_stripe_customer_payment_method')
+
+ def on_change_party(self):
+ try:
+ super().on_change_party()
+ except AttributeError:
+ pass
+ self.stripe_customer = None
+ self.stripe_customer_source = None
+ self.stripe_customer_source_selection = None
+
+ @fields.depends('journal')
+ def on_change_with_stripe_account(self, name=None):
+ if self.journal and self.journal.process_method == 'stripe':
+ return self.journal.stripe_account.id
+
+ @fields.depends('stripe_customer', 'stripe_customer_source')
+ def get_stripe_customer_sources(self):
+ sources = [('', '')]
+ if self.stripe_customer:
+ sources.extend(self.stripe_customer.sources())
+ if (self.stripe_customer_source
+ and self.stripe_customer_source not in dict(sources)):
+ sources.append(
+ (self.stripe_customer_source, self.stripe_customer_source))
+ return sources
+
+ @fields.depends(
+ 'stripe_customer_source_selection',
+ 'stripe_customer_source')
+ def on_change_stripe_customer_source_selection(self):
+ self.stripe_customer_source = self.stripe_customer_source_selection
+
+ def get_stripe_customer_source(self, name):
+ return self.stripe_customer_source
+
+ @classmethod
+ def set_stripe_customer_source(cls, payments, name, value):
+ pass
+
+ @fields.depends('stripe_customer', 'stripe_customer_payment_method')
+ def get_stripe_customer_payment_methods(self):
+ methods = [('', '')]
+ if self.stripe_customer:
+ methods.extend(self.stripe_customer.payment_methods())
+ if (self.stripe_customer_payment_method
+ and self.stripe_customer_payment_method not in dict(methods)):
+ methods.append(
+ (self.stripe_customer_payment_method,
+ self.stripe_customer_payment_method))
+ return methods
+
+ @fields.depends(
+ 'stripe_customer_payment_method_selection',
+ 'stripe_customer_payment_method')
+ def on_change_stripe_customer_payment_method_selection(self):
+ self.stripe_customer_payment_method = (
+ self.stripe_customer_payment_method_selection)
+
+ def get_stripe_customer_payment_method(self, name):
+ return self.stripe_customer_payment_method
+
+ @classmethod
+ def set_stripe_customer_payment_method(cls, payments, name, value):
+ pass
diff -r 92d7812129fc -r a84c94e1d191 party.py
--- a/party.py Mon Oct 11 18:22:19 2021 +0200
+++ b/party.py Mon Oct 11 18:35:28 2021 +0200
@@ -3,6 +3,8 @@
from trytond.pool import PoolMeta, Pool
from trytond.model import fields
+from .common import StripeCustomerMethodMixin
+
class Party(metaclass=PoolMeta):
__name__ = 'party.party'
@@ -29,6 +31,19 @@
Customer.__queue__.stripe_update(to_update)
+class PartyReceptionDirectDebit(
+ StripeCustomerMethodMixin, metaclass=PoolMeta):
+ __name__ = 'party.party.reception_direct_debit'
+
+ def _get_payment(self, line, date, amount):
+ payment = super()._get_payment(line, date, amount)
+ self.stripe_customer = self.stripe_customer
+ self.stripe_customer_source = self.stripe_customer_source
+ self.stripe_customer_payment_method = (
+ self.stripe_customer_payment_method)
+ return payment
+
+
class Replace(metaclass=PoolMeta):
__name__ = 'party.replace'
diff -r 92d7812129fc -r a84c94e1d191 party.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/party.xml Mon Oct 11 18:35:28 2021 +0200
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tryton>
+ <data>
+ <record model="ir.ui.view" id="party_reception_direct_debit_view_form">
+ <field name="model">party.party.reception_direct_debit</field>
+ <field name="inherit"
ref="account_payment.party_reception_direct_debit_view_form"/>
+ <field name="name">party_reception_direct_debit_form</field>
+ </record>
+ </data>
+</tryton>
diff -r 92d7812129fc -r a84c94e1d191 payment.py
--- a/payment.py Mon Oct 11 18:22:19 2021 +0200
+++ b/payment.py Mon Oct 11 18:35:28 2021 +0200
@@ -16,7 +16,7 @@
from trytond.model import (
ModelSQL, ModelView, Workflow, DeactivableMixin, fields, dualmethod)
from trytond.pool import PoolMeta, Pool
-from trytond.pyson import Eval, Bool
+from trytond.pyson import Eval
from trytond.report import Report, get_email
from trytond.rpc import RPC
from trytond.sendmail import sendmail_transactional
@@ -30,6 +30,8 @@
ProcessError, PaymentValidationError)
from trytond.modules.currency.fields import Monetary
+from .common import StripeCustomerMethodMixin
+
logger = logging.getLogger(__name__)
stripe.max_network_retries = config.getint(
'account_payment_stripe', 'max_network_retries', default=3)
@@ -118,7 +120,7 @@
}
-class Payment(CheckoutMixin, metaclass=PoolMeta):
+class Payment(StripeCustomerMethodMixin, CheckoutMixin, metaclass=PoolMeta):
__name__ = 'account.payment'
stripe_checkout_needed = fields.Function(
@@ -192,76 +194,6 @@
states={
'invisible': ~Eval('stripe_dispute_status'),
})
- stripe_customer = fields.Many2One(
- 'account.payment.stripe.customer', "Stripe Customer",
- domain=[
- ('party', '=', Eval('party', -1)),
- ('stripe_account', '=', Eval('stripe_account', -1)),
- ],
- states={
- 'invisible': Eval('process_method') != 'stripe',
- 'required': Bool(Eval('stripe_customer_source')),
- 'readonly': (~Eval('state').in_(['draft', 'approved'])
- | Eval('stripe_token') | Eval('stripe_payment_intent_id')),
- },
- depends=['party', 'stripe_account', 'process_method',
- 'stripe_customer_source', 'stripe_token',
- 'stripe_payment_intent_id', 'state'])
- stripe_customer_source = fields.Char(
- "Stripe Customer Source",
- states={
- 'invisible': ((Eval('process_method') != 'stripe')
- | Eval('stripe_token')
- | Eval('stripe_payment_intent_id')
- | ~Eval('stripe_customer')),
- 'readonly': ~Eval('state').in_(['draft', 'approved']),
- },
- depends=['process_method', 'stripe_token', 'stripe_payment_intent_id',
- 'stripe_customer', 'state'])
- # Use Function field with selection to avoid to query Stripe
- # to validate the value
- stripe_customer_source_selection = fields.Function(fields.Selection(
- 'get_stripe_customer_sources', "Stripe Customer Source",
- states={
- 'invisible': ((Eval('process_method') != 'stripe')
- | Eval('stripe_token')
- | Eval('stripe_payment_intent_id')
- | ~Eval('stripe_customer')),
- 'readonly': ~Eval('state').in_(['draft', 'approved']),
- },
- depends=[
- 'process_method', 'stripe_token', 'stripe_customer', 'state']),
- 'get_stripe_customer_source', setter='set_stripe_customer_source')
- stripe_customer_payment_method = fields.Char(
- "Stripe Payment Method",
- states={
- 'invisible': ((Eval('process_method') != 'stripe')
- | Eval('stripe_token')
- | ~Eval('stripe_customer')),
- 'readonly': (~Eval('state').in_(['draft', 'approved'])
- | Eval('stripe_payment_intent_id')),
- },
- depends=['process_method', 'stripe_token', 'stripe_customer', 'state'])
- # Use Function field with selection to avoid to query Stripe
- # to validate the value
- stripe_customer_payment_method_selection = fields.Function(
- fields.Selection(
- 'get_stripe_customer_payment_methods',
- "Stripe Customer Payment Method",
- states={
- 'invisible': ((Eval('process_method') != 'stripe')
- | Eval('stripe_token')
- | ~Eval('stripe_customer')),
- 'readonly': (~Eval('state').in_(['draft', 'approved'])
- | Eval('stripe_payment_intent_id')),
- },
- depends=[
- 'process_method', 'stripe_token', 'stripe_customer', 'state']),
- 'get_stripe_customer_payment_method',
- setter='set_stripe_customer_payment_method')
- stripe_account = fields.Function(fields.Many2One(
- 'account.payment.stripe.account', "Stripe Account"),
- 'on_change_with_stripe_account')
stripe_amount = fields.Function(
fields.Integer("Stripe Amount"),
'get_stripe_amount', setter='set_stripe_amount')
@@ -278,6 +210,44 @@
@classmethod
def __setup__(cls):
super(Payment, cls).__setup__()
+
+ cls.stripe_customer.states['readonly'] = (
+ ~Eval('state').in_(['draft', 'approved'])
+ | Eval('stripe_token')
+ | Eval('stripe_payment_intent_id'))
+ cls.stripe_customer.depends.extend(
+ ['state', 'stripe_token', 'stripe_payment_intent_id'])
+
+ cls.stripe_customer_source.states['invisible'] |= (
+ Eval('stripe_token') | Eval('stripe_payment_intent_id'))
+ cls.stripe_customer_source.states['readonly'] = (
+ ~Eval('state').in_(['draft', 'approved']))
+ cls.stripe_customer_source.depends.extend(
+ ['stripe_token', 'stripe_payment_intent_id', 'state'])
+
+ cls.stripe_customer_source_selection.states['invisible'] |= (
+ Eval('stripe_token') | Eval('stripe_payment_intent_id'))
+ cls.stripe_customer_source_selection.states['readonly'] = (
+ ~Eval('state').in_(['draft', 'approved']))
+ cls.stripe_customer_source_selection.depends.extend(
+ ['stripe_token', 'stripe_payment_intent_id', 'state'])
+
+ cls.stripe_customer_payment_method.states['invisible'] |= (
+ Eval('stripe_token'))
+ cls.stripe_customer_payment_method.states['readonly'] = (
+ ~Eval('state').in_(['draft', 'approved'])
+ | Eval('stripe_payment_intent_id'))
+ cls.stripe_customer_payment_method.depends.extend(
+ ['stripe_token', 'state', 'stripe_payment_intent_id'])
+
+ cls.stripe_customer_payment_method_selection.states['invisible'] |= (
+ Eval('stripe_token'))
+ cls.stripe_customer_payment_method_selection.states['readonly'] = (
+ ~Eval('state').in_(['draft', 'approved'])
+ | Eval('stripe_payment_intent_id'))
+ cls.stripe_customer_payment_method_selection.depends.extend(
+ ['stripe_token', 'state', 'stripe_payment_intent_id'])
+
cls.amount.states['readonly'] &= ~Eval('stripe_capture_needed')
cls.amount.depends.append('stripe_capture_needed')
cls.stripe_amount.states.update(cls.amount.states)
@@ -330,63 +300,6 @@
def default_stripe_idempotency_key(cls):
return uuid.uuid4().hex
- @fields.depends('party')
- def on_change_party(self):
- super(Payment, self).on_change_party()
- self.stripe_customer = None
- self.stripe_customer_source = None
- self.stripe_customer_source_selection = None
-
- @fields.depends('stripe_customer', 'stripe_customer_source')
- def get_stripe_customer_sources(self):
- sources = [('', '')]
- if self.stripe_customer:
- sources.extend(self.stripe_customer.sources())
- if (self.stripe_customer_source
- and self.stripe_customer_source not in dict(sources)):
- sources.append(
- (self.stripe_customer_source, self.stripe_customer_source))
- return sources
-
- @fields.depends(
- 'stripe_customer_source_selection',
- 'stripe_customer_source')
- def on_change_stripe_customer_source_selection(self):
- self.stripe_customer_source = self.stripe_customer_source_selection
-
- def get_stripe_customer_source(self, name):
- return self.stripe_customer_source
-
- @classmethod
- def set_stripe_customer_source(cls, payments, name, value):
- pass
-
- @fields.depends('stripe_customer', 'stripe_customer_payment_method')
- def get_stripe_customer_payment_methods(self):
- methods = [('', '')]
- if self.stripe_customer:
- methods.extend(self.stripe_customer.payment_methods())
- if (self.stripe_customer_payment_method
- and self.stripe_customer_payment_method not in dict(methods)):
- methods.append(
- (self.stripe_customer_payment_method,
- self.stripe_customer_payment_method))
- return methods
-
- @fields.depends(
- 'stripe_customer_payment_method_selection',
- 'stripe_customer_payment_method')
- def on_change_stripe_customer_payment_method_selection(self):
- self.stripe_customer_payment_method = (
- self.stripe_customer_payment_method_selection)
-
- def get_stripe_customer_payment_method(self, name):
- return self.stripe_customer_payment_method
-
- @classmethod
- def set_stripe_customer_payment_method(cls, payments, name, value):
- pass
-
@fields.depends('process_method',
'stripe_token', 'stripe_payment_intent_id',
'stripe_customer_source', 'stripe_customer_source_selection',
@@ -406,11 +319,6 @@
and not self.stripe_capture
and not self.stripe_captured)
- @fields.depends('journal')
- def on_change_with_stripe_account(self, name=None):
- if self.journal and self.journal.process_method == 'stripe':
- return self.journal.stripe_account.id
-
def get_stripe_amount(self, name):
return int(self.amount * 10 ** self.currency.digits)
diff -r 92d7812129fc -r a84c94e1d191 tryton.cfg
--- a/tryton.cfg Mon Oct 11 18:22:19 2021 +0200
+++ b/tryton.cfg Mon Oct 11 18:35:28 2021 +0200
@@ -7,4 +7,5 @@
party
xml:
payment.xml
+ party.xml
message.xml
diff -r 92d7812129fc -r a84c94e1d191 view/party_reception_direct_debit_form.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/view/party_reception_direct_debit_form.xml Mon Oct 11 18:35:28
2021 +0200
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<data>
+ <xpath expr="//field[@name='currency']" position="after">
+ <label name="stripe_customer" string="Customer:"/>
+ <field name="stripe_customer" colspan="3"/>
+
+ <label name="stripe_customer_source_selection" string="Source:"/>
+ <field name="stripe_customer_source_selection" colspan="3"/>
+
+ <label name="stripe_customer_payment_method_selection"
string="Payment Method:"/>
+ <field name="stripe_customer_payment_method_selection"
colspan="3"/>
+
+ <field name="stripe_customer_source" colspan="4" invisible="1"/>
+ <field name="stripe_customer_payment_method" colspan="4"
invisible="1"/>
+ </xpath>
+</data>