1# -*- coding: utf-8 -*-
2# Part of Odoo. See LICENSE file for full copyright and licensing details.
3
4from datetime import datetime
5from pytz import UTC
6
7from odoo import api, fields, models
8from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
9
10
11class AdyenTransaction(models.Model):
12    _name = 'adyen.transaction'
13    _description = 'Adyen for Platforms Transaction'
14    _order = 'date desc'
15
16    adyen_account_id = fields.Many2one('adyen.account')
17    reference = fields.Char('Reference')
18    amount = fields.Float('Amount')
19    currency_id = fields.Many2one('res.currency', string='Currency')
20    date = fields.Datetime('Date')
21    description = fields.Char('Description')
22    status = fields.Selection(string='Type', selection=[
23        ('PendingCredit', 'Pending Credit'),
24        ('CreditFailed', 'Credit Failed'),
25        ('Credited', 'Credited'),
26        ('Converted', 'Converted'),
27        ('PendingDebit', 'Pending Debit'),
28        ('DebitFailed', 'Debit Failed'),
29        ('Debited', 'Debited'),
30        ('DebitReversedReceived', 'Debit Reversed Received'),
31        ('DebitedReversed', 'Debit Reversed'),
32        ('ChargebackReceived', 'Chargeback Received'),
33        ('Chargeback', 'Chargeback'),
34        ('ChargebackReversedReceived', 'Chargeback Reversed Received'),
35        ('ChargebackReversed', 'Chargeback Reversed'),
36        ('Payout', 'Payout'),
37        ('PayoutReversed', 'Payout Reversed'),
38        ('FundTransfer', 'Fund Transfer'),
39        ('PendingFundTransfer', 'Pending Fund Transfer'),
40        ('ManualCorrected', 'Manual Corrected'),
41    ])
42    adyen_payout_id = fields.Many2one('adyen.payout')
43
44    @api.model
45    def sync_adyen_transactions(self):
46        ''' Method called by cron to sync transactions from Adyen.
47            Updates the status of pending transactions and create missing ones.
48        '''
49        for payout_id in self.env['adyen.payout'].search([]):
50            page = 1
51            has_next_page = True
52            new_transactions = True
53            pending_statuses = ['PendingCredit', 'PendingDebit', 'DebitReversedReceived', 'ChargebackReceived', 'ChargebackReversedReceived', 'PendingFundTransfer']
54            pending_transaction_ids = payout_id.transaction_ids.filtered(lambda tr: tr.status in pending_statuses)
55
56            while has_next_page and (new_transactions or pending_transaction_ids):
57                # Fetch next transaction page
58                transactions, has_next_page = payout_id._fetch_transactions(page)
59                for transaction in transactions:
60                    transaction_reference = transaction.get('paymentPspReference') or transaction.get('pspReference')
61                    transaction_id = payout_id.transaction_ids.filtered(lambda tr: tr.reference == transaction_reference)
62                    if transaction_id:
63                        new_transactions = False
64                        if transaction_id in pending_transaction_ids:
65                            # Update transaction status
66                            transaction_id.sudo().write({
67                                'status': transaction['transactionStatus'],
68                            })
69                            pending_transaction_ids -= transaction_id
70                    else:
71                        currency_id = self.env['res.currency'].search([('name', '=', transaction['amount']['currency'])])
72                        # New transaction
73                        self.env['adyen.transaction'].sudo().create({
74                            'adyen_account_id': payout_id.adyen_account_id.id,
75                            'reference': transaction_reference,
76                            'amount': transaction['amount']['value'] / (10 ** currency_id.decimal_places),
77                            'currency_id': currency_id.id,
78                            'date': datetime.strptime(transaction['creationDate'], '%Y-%m-%dT%H:%M:%S%z').astimezone(UTC).strftime(DEFAULT_SERVER_DATETIME_FORMAT),
79                            'description': transaction.get('description'),
80                            'status': transaction['transactionStatus'],
81                            'adyen_payout_id': payout_id.id,
82                        })
83                page += 1
84