From 839bbc34ac17e0f64eb53512c8823564834bb7fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D8=B4=D8=B1=D9=83=D8=A9=20=D8=AE=D8=A8=D9=8A=D8=B1=20?= =?UTF-8?q?=D8=A7=D9=84=D9=85=D8=AD=D8=AF=D9=88=D8=AF=D8=A9?= Date: Wed, 6 Aug 2025 15:48:54 +0300 Subject: [PATCH 1/3] Update dev-preprod-servers.yml --- .github/workflows/dev-preprod-servers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-preprod-servers.yml b/.github/workflows/dev-preprod-servers.yml index 0e4906744..dd53a1f34 100644 --- a/.github/workflows/dev-preprod-servers.yml +++ b/.github/workflows/dev-preprod-servers.yml @@ -84,7 +84,7 @@ jobs: run: | sudo chmod +x /home/${{ secrets.CLIENT_USER }}/scripts/pull/dev_pull_standard_code.sh sudo /home/${{ secrets.CLIENT_USER }}/scripts/pull/dev_pull_standard_code.sh - sudo systemctl restart ${{ secrets.ENSAN_APP_TEST_SERVICE }} ${{ secrets.ODEX25_GENERAL_TEST_SERVICE }} ${{ secrets.ODEX25_STANDARD_TEST_SERVICE }} ${{ secrets.TWAHOD_APP_TEST_SERVICE }} ${{ secrets.HELPDESK_TEST_SERVICE }} ${{ secrets.KAZ_LIBRARY_TEST_SERVICE }} ${{ secrets.TRAHUM_TEST_SERVICE }} ${{ secrets.CYBER_APP_TEST_SERVICE }} + sudo systemctl restart ${{ secrets.ENSAN_APP_TEST_SERVICE }} ${{ secrets.ODEX25_GENERAL_TEST_SERVICE }} ${{ secrets.ODEX25_STANDARD_TEST_SERVICE }} ${{ secrets.TWAHOD_APP_TEST_SERVICE }} ${{ secrets.HELPDESK_TEST_SERVICE }} ${{ secrets.KAZ_LIBRARY_TEST_SERVICE }} ${{ secrets.CYBER_APP_TEST_SERVICE }} if [ $? -eq 0 ]; then echo "** [INFO] "DEV" services have been restarted." else From 1963c56d7519430d130b622ee7cd4da44c02290d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D8=B4=D8=B1=D9=83=D8=A9=20=D8=AE=D8=A8=D9=8A=D8=B1=20?= =?UTF-8?q?=D8=A7=D9=84=D9=85=D8=AD=D8=AF=D9=88=D8=AF=D8=A9?= Date: Wed, 6 Aug 2025 15:49:33 +0300 Subject: [PATCH 2/3] Update dev-preprod-servers.yml --- .github/workflows/dev-preprod-servers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-preprod-servers.yml b/.github/workflows/dev-preprod-servers.yml index dd53a1f34..e72328976 100644 --- a/.github/workflows/dev-preprod-servers.yml +++ b/.github/workflows/dev-preprod-servers.yml @@ -68,7 +68,7 @@ jobs: run: | sudo chmod +x /home/${{ secrets.CLIENT_USER }}/scripts/pull/preprod_pull_standard_code.sh sudo /home/${{ secrets.CLIENT_USER }}/scripts/pull/preprod_pull_standard_code.sh - sudo systemctl restart ${{ secrets.ENSAN_APP_PREPROD_SERVICE }} ${{ secrets.ODEX25_GENERAL_PREPROD_SERVICE }} ${{ secrets.ODEX25_STANDARD_PREPROD_SERVICE }} ${{ secrets.TWAHOD_APP_PREPROD_SERVICE }} ${{ secrets.ODEX25_DEMO_PREPROD_SERVICE }} ${{ secrets.HELPDESK_PREPROD_SERVICE }} ${{ secrets.TRAHUM_PREPROD_SERVICE }} ${{ secrets.CYBER_APP_PREPROD_SERVICE }} + sudo systemctl restart ${{ secrets.ENSAN_APP_PREPROD_SERVICE }} ${{ secrets.ODEX25_GENERAL_PREPROD_SERVICE }} ${{ secrets.ODEX25_STANDARD_PREPROD_SERVICE }} ${{ secrets.TWAHOD_APP_PREPROD_SERVICE }} ${{ secrets.ODEX25_DEMO_PREPROD_SERVICE }} ${{ secrets.HELPDESK_PREPROD_SERVICE }} ${{ secrets.CYBER_APP_PREPROD_SERVICE }} if [ $? -eq 0 ]; then echo "** [INFO] "PREPROD" services have been restarted." else From 16e133f1f6652992eb1132e97c975c89380a9cf8 Mon Sep 17 00:00:00 2001 From: Abdurrahman Saber Date: Thu, 7 Aug 2025 06:47:54 +0300 Subject: [PATCH 3/3] [FIX] * errors in transaction confirmation , sms, portal actions --- .../models/donation_recurring.py | 29 ++++++++-- .../models/sale_order.py | 11 ++-- .../payment_applepay/controllers/main.py | 2 +- .../controllers/main.py | 54 +++++++++---------- .../models/recurring_donation.py | 26 ++++++++- 5 files changed, 84 insertions(+), 38 deletions(-) diff --git a/odex25_donation/ensan_donation_request/models/donation_recurring.py b/odex25_donation/ensan_donation_request/models/donation_recurring.py index bb3b37a8d..d08f1e034 100644 --- a/odex25_donation/ensan_donation_request/models/donation_recurring.py +++ b/odex25_donation/ensan_donation_request/models/donation_recurring.py @@ -206,6 +206,7 @@ class DonationRecurring(models.Model): # return picking def action_activate(self): + bot = self.env.ref('base.partner_root').id for rec in self: rec.name = self.env['ir.sequence'].next_by_code('donation.recurring') or _('New') for line in rec.recurring_line_ids: @@ -219,10 +220,12 @@ class DonationRecurring(models.Model): rec._message_sms_with_template( template=template, partner_ids=rec.partner_id.ids, - put_in_queue=True + put_in_queue=True, + author_id=bot ) def action_pause(self): + bot = self.env.ref('base.partner_root').id for record in self: record.state = 'paused' template = self.env.company.donation_recurring_paused_sms_template_id @@ -232,10 +235,12 @@ class DonationRecurring(models.Model): record._message_sms_with_template( template=template, partner_ids=record.partner_id.ids, - put_in_queue=True + put_in_queue=True, + author_id=bot ) def action_resume(self): + bot = self.env.ref('base.partner_root').id today = fields.Date.context_today(self) for record in self: if record.state != 'active': @@ -262,13 +267,27 @@ class DonationRecurring(models.Model): record._message_sms_with_template( template=template, partner_ids=record.partner_id.ids, - put_in_queue=True + put_in_queue=True, + author_id=bot ) def action_cancel(self): + template = self.env.company.donation_recurring_cancelled_sms_template_id + bot = self.env.ref('base.partner_root').id + + if not template: + raise ValidationError( + _("⚠️ SMS template for 'Cancel Recurring Donation' is not configured in Company settings.") + ) for record in self: record.state = 'cancel' record.date_end = fields.Date.context_today(self) + record._message_sms_with_template( + template=template, + partner_ids=record.partner_id.ids, + put_in_queue=True, + author_id=bot + ) def action_reset_to_active(self): for record in self: @@ -323,6 +342,7 @@ class DonationRecurring(models.Model): rec.recurring_next_date += relativedelta(months=interval) def unlink(self): + bot = self.env.ref('base.partner_root').id for rec in self: if rec.state == 'active': raise UserError( @@ -335,7 +355,8 @@ class DonationRecurring(models.Model): rec._message_sms_with_template( template=template, partner_ids=rec.partner_id.ids, - put_in_queue=True + put_in_queue=True, + author_id=bot ) return super(DonationRecurring, self).unlink() diff --git a/odex25_donation/ensan_sale_management/models/sale_order.py b/odex25_donation/ensan_sale_management/models/sale_order.py index 523dee391..030715a0c 100644 --- a/odex25_donation/ensan_sale_management/models/sale_order.py +++ b/odex25_donation/ensan_sale_management/models/sale_order.py @@ -101,6 +101,7 @@ class SaleOrder(models.Model): def action_confirm(self): res = super().action_confirm() + bot = self.env.ref('base.partner_root').id if res: sms_template_id = self.env.ref('ensan_sale_management.sms_template_data_donation') donar_sms_template_id = self.env.ref('ensan_sale_management.sms_template_donors_data_donation') @@ -110,13 +111,15 @@ class SaleOrder(models.Model): rec._message_sms_with_template( template=sms_template_id, put_in_queue=False, - sms_numbers=[rec.order_mobile_number] + partner_ids=rec.partner_id.ids, + author_id=bot ) for donator in rec.donators_ids: donator._message_sms_with_template( template=donar_sms_template_id, put_in_queue=False, - sms_numbers=[donator.donator_mobile_number] + sms_numbers=[donator.donator_mobile_number], + author_id=bot ) return res @@ -170,13 +173,15 @@ class SaleOrder(models.Model): @api.model def _cron_send_recovery_sms(self): + bot = self.env.ref('base.partner_root').id records = self.search([('is_abandoned_cart', '=', True), ('cart_recovery_sms_sent', '=', False)]) for rec in records: sms_template_id = rec.website_id.cart_recovery_sms_template_id rec._message_sms_with_template( template=sms_template_id, put_in_queue=True, - partner_ids=rec.partner_id.ids + partner_ids=rec.partner_id.ids, + author_id=bot ) records.write({'cart_recovery_sms_sent': True}) diff --git a/odex25_donation/payment_applepay/controllers/main.py b/odex25_donation/payment_applepay/controllers/main.py index dc02b53e9..1f8731017 100644 --- a/odex25_donation/payment_applepay/controllers/main.py +++ b/odex25_donation/payment_applepay/controllers/main.py @@ -58,7 +58,7 @@ class ApplepayController(http.Controller): phone = '+' + '966' + phone return phone.replace('+', '') - @http.route('/payment/applepay/return', type='http', auth='public', csrf=False) + @http.route('/payment/applepay/return', type='http', auth='public', website=True, csrf=False) def applepay_return(self, **post): """ applepay.""" acquirer = request.env['payment.acquirer'].sudo().search([('provider', '=', 'applepay')], limit=1) diff --git a/odex25_donation/payment_hyperpay_tokenization/controllers/main.py b/odex25_donation/payment_hyperpay_tokenization/controllers/main.py index ac22dce8c..d0603d775 100644 --- a/odex25_donation/payment_hyperpay_tokenization/controllers/main.py +++ b/odex25_donation/payment_hyperpay_tokenization/controllers/main.py @@ -1,11 +1,12 @@ import requests import re +import logging from odoo.http import route, request, Controller from odoo.addons.payment_hyperpay.data.payment_icon import payment_icon from odoo.addons.payment.controllers.portal import PaymentProcessing - +_logger = logging.getLogger(__name__) TEST_URL = "https://eu-test.oppwa.com" LIVE_URL = "https://eu-prod.oppwa.com" @@ -88,41 +89,36 @@ class HyperPayTokenization(Controller): @route('/hyperpay/tokens/result', type='http', auth='public', website=True) def token_return(self, **post): try: - if post.get('transaction_id'): - transaction = request.env['payment.transaction'].sudo().search([('id', '=', int(post.get('transaction_id')))]) - if transaction: - transaction.s2s_do_refund() + acquirer_id = request.env['payment.acquirer'].sudo().search([('id', '=', int(post.get('acquirer_id', 0)))]) + + if acquirer_id.state == 'test': + domain = TEST_URL else: - acquirer_id = request.env['payment.acquirer'].sudo().search([('id', '=', int(post.get('acquirer_id', 0)))]) + domain = LIVE_URL - if acquirer_id.state == 'test': - domain = TEST_URL - else: - domain = LIVE_URL + url = f"{domain}{post.get('resourcePath')}?entityId={acquirer_id.hyperpay_merchant_id}" + headers = { + "Authorization": f"Bearer {acquirer_id.hyperpay_authorization}" + } + resp = requests.get(url=url, headers=headers).json() + result = resp.get('result', {}) + result_code = result.get('code') - url = f"{domain}{post.get('resourcePath')}?entityId={acquirer_id.hyperpay_merchant_id}" - headers = { - "Authorization": f"Bearer {acquirer_id.hyperpay_authorization}" - } - resp = requests.get(url=url, headers=headers).json() - result = resp.get('result', {}) - result_code = result.get('code') + if result_code and not re.match(r"^(000\.000\.|000\.100\.1|000\.[36]|000\.400\.1[12]0|000\.400\.0[^3]|000\.400\.100|000\.200)", result_code): + # Handle failed cards logic here + return {'state': False, 'message': result.get('description', ''), 'errors': resp.get('parameterErrors', [])} - if result_code and not re.match(r"^(000\.000\.|000\.100\.1|000\.[36]|000\.400\.1[12]0|000\.400\.0[^3]|000\.400\.100|000\.200)", result_code): - # Handle failed cards logic here - return {'state': False, 'message': result.get('description', ''), 'errors': resp.get('parameterErrors', [])} - - # create card record and activate recurring donation - card = resp.get('card', {}) - if not card: - return {'state': False, 'message': 'Card data not found'} - self._post_process_token_return(resp) + # create card record and activate recurring donation + card = resp.get('card', {}) + if not card: + return {'state': False, 'message': 'Card data not found'} + self._post_process_token_return(resp) except Exception as er: - request.env.cr.rollback() - raise er - + # request.env.cr.rollback() + _logger.error(er) return request.redirect('/my/recurring_donation') + def _post_process_token_return(self, data): acquirer_id = int(data.get('customParameters', {}).get('SHOPPER_acquirer_id', 0)) card = data.get('card', {}) diff --git a/odex25_donation/recurring_donation_payment/models/recurring_donation.py b/odex25_donation/recurring_donation_payment/models/recurring_donation.py index ec8e63352..cb477e7da 100644 --- a/odex25_donation/recurring_donation_payment/models/recurring_donation.py +++ b/odex25_donation/recurring_donation_payment/models/recurring_donation.py @@ -1,5 +1,9 @@ -from odoo import models, fields, _ +import psycopg2 +from odoo import models, fields, _, api from odoo.exceptions import ValidationError +import logging + +_logger = logging.getLogger(__name__) class RecurringDonation(models.Model): _inherit = 'donation.recurring' @@ -16,6 +20,16 @@ class RecurringDonation(models.Model): def _recurring_confirm_sale_order(self, order): transaction_id = self._create_payment_transaction(order) if transaction_id.state == 'done': + try: + transaction_id._post_process_after_done() + except psycopg2.OperationalError as e: + # Serialization Error, Try again in cron + self.env.cr.rollback() + except Exception as e: + # Unknown Error, Mute for front-end and log + self.env.cr.rollback() + _logger.exception("Error while processing transaction(s) %s, exception \"%s\"", transaction_id.ids, str(e)) + return super()._recurring_confirm_sale_order(order) return False @@ -35,3 +49,13 @@ class RecurringDonation(models.Model): return self.preferred_payment_token_id.id return self.env['payment.token'].sudo().search([('partner_id', '=', self.partner_id.id), ('verified', '=', True)], limit=1).id + + +class ReportInvoiceWithPayment(models.AbstractModel): + _inherit = 'report.account.report_invoice_with_payments' + + @api.model + def _get_report_values(self, docids, data=None): + rslt = super()._get_report_values(docids, data) + rslt['company'] = self.env.company + return rslt