Files
tryton/modules/web_shop_shopify/account.py
T

135 lines
5.0 KiB
Python
Raw Normal View History

2021-10-12 10:15:55 +02:00
# 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 collections import defaultdict
from decimal import Decimal
from trytond.model import Unique
2021-12-11 17:58:45 +01:00
from trytond.pool import Pool, PoolMeta
2021-10-12 10:15:55 +02:00
from .common import IdentifierMixin
class Payment(IdentifierMixin, metaclass=PoolMeta):
__name__ = 'account.payment'
@classmethod
def __setup__(cls):
super().__setup__()
t = cls.__table__()
cls._sql_constraints += [
('shopify_identifier_unique',
Unique(t, t.shopify_identifier_signed),
'web_shop_shopify.msg_identifier_payment_unique'),
]
@classmethod
def _get_shopify_payment_journal_pattern(cls, sale, transaction):
return {
'gateway': transaction.gateway,
}
@classmethod
def _get_from_shopify(cls, sale, transaction):
assert transaction.kind in {'authorization', 'sale'}
payment = cls(shopify_identifier=transaction.id)
payment.company = sale.company
payment.journal = sale.web_shop.get_payment_journal(
transaction.currency,
cls._get_shopify_payment_journal_pattern(
sale, transaction))
payment.kind = 'receivable'
payment.amount = Decimal(transaction.amount)
payment.origin = sale
payment.party = sale.party
return payment
@classmethod
def get_from_shopify(cls, sale, order):
pool = Pool()
Group = pool.get('account.payment.group')
id2payments = {}
to_process = defaultdict(list)
transactions = [
t for t in order.transactions() if t.status == 'success']
# Order transactions to process parent first
kinds = ['authorization', 'capture', 'sale', 'void', 'refund']
transactions.sort(key=lambda t: kinds.index(t.kind))
amounts = defaultdict(Decimal)
for transaction in transactions:
if transaction.kind not in {'authorization', 'sale'}:
continue
payments = cls.search([
('shopify_identifier', '=', transaction.id),
])
if payments:
payment, = payments
else:
payment = cls._get_from_shopify(sale, transaction)
to_process[payment.company, payment.journal].append(payment)
id2payments[transaction.id] = payment
amounts[transaction.id] = Decimal(transaction.amount)
cls.save(list(id2payments.values()))
for (company, journal), payments in to_process.items():
group = Group(
company=company,
journal=journal,
kind='receivable')
group.save()
2022-04-11 20:41:56 +02:00
cls.submit(payments)
2021-10-12 10:15:55 +02:00
cls.process(payments, lambda: group)
captured = defaultdict(Decimal)
voided = defaultdict(Decimal)
refunded = defaultdict(Decimal)
for transaction in transactions:
if transaction.kind == 'sale':
payment = id2payments[transaction.id]
captured[payment] += Decimal(transaction.amount)
elif transaction.kind == 'capture':
payment = id2payments[transaction.parent_id]
id2payments[transaction.id] = payment
captured[payment] += Decimal(transaction.amount)
elif transaction.kind == 'void':
payment = id2payments[transaction.parent_id]
voided[payment] += Decimal(transaction.amount)
elif transaction.kind == 'refund':
payment = id2payments[transaction.parent_id]
captured[payment] -= Decimal(transaction.amount)
refunded[payment] += Decimal(transaction.amount)
to_save = []
for payment in id2payments.values():
if captured[payment] and payment.amount != captured[payment]:
payment.amount = captured[payment]
to_save.append(payment)
cls.proceed(to_save)
cls.save(to_save)
to_succeed, to_fail, to_proceed = set(), set(), set()
for transaction_id, payment in id2payments.items():
if amounts[transaction_id] == (
captured[payment] + voided[payment] + refunded[payment]):
if payment.amount:
if payment.state != 'succeeded':
to_succeed.add(payment)
else:
if payment.state != 'failed':
to_fail.add(payment)
elif payment.state != 'processing':
to_proceed.add(payment)
cls.fail(to_fail)
cls.proceed(to_proceed)
cls.succeed(to_succeed)
return list(id2payments.values())
class PaymentJournal(metaclass=PoolMeta):
__name__ = 'account.payment.journal'
@classmethod
def __setup__(cls):
super().__setup__()
cls.process_method.selection.append(('shopify', "Shopify"))