changes
This commit is contained in:
@@ -467,7 +467,9 @@ class PoyntController(http.Controller):
|
||||
def poynt_process_card(self, reference=None, poynt_order_id=None,
|
||||
card_number=None, exp_month=None, exp_year=None,
|
||||
cvv=None, cardholder_name=None, card_type=None,
|
||||
**kwargs):
|
||||
billing_address=None, billing_city=None,
|
||||
billing_state=None, billing_zip=None,
|
||||
billing_country=None, **kwargs):
|
||||
"""Process a card payment through Poynt Cloud API.
|
||||
|
||||
The frontend sends card details which are passed to Poynt for
|
||||
@@ -503,6 +505,13 @@ class PoyntController(http.Controller):
|
||||
},
|
||||
'verificationData': {
|
||||
'cvData': cvv,
|
||||
'cardHolderBillingAddress': {
|
||||
'line1': billing_address or '',
|
||||
'city': billing_city or '',
|
||||
'territory': billing_state or '',
|
||||
'postalCode': billing_zip or '',
|
||||
'countryCode': billing_country or '',
|
||||
},
|
||||
},
|
||||
'entryDetails': {
|
||||
'customerPresenceStatus': 'ECOMMERCE',
|
||||
@@ -510,13 +519,25 @@ class PoyntController(http.Controller):
|
||||
},
|
||||
}
|
||||
|
||||
action = 'AUTHORIZE' if tx_sudo.provider_id.capture_manually else 'SALE'
|
||||
provider = tx_sudo.provider_id.sudo()
|
||||
action = 'AUTHORIZE' if provider.capture_manually else 'SALE'
|
||||
minor_amount = poynt_utils.format_poynt_amount(
|
||||
tx_sudo.amount, tx_sudo.currency_id,
|
||||
)
|
||||
|
||||
context = {
|
||||
'source': 'WEB',
|
||||
'sourceApp': 'odoo.fusion_poynt',
|
||||
'transactionInstruction': 'ONLINE_AUTH_REQUIRED',
|
||||
}
|
||||
if provider.poynt_business_id:
|
||||
context['businessId'] = provider.poynt_business_id
|
||||
if provider.poynt_store_id:
|
||||
context['storeId'] = provider.poynt_store_id
|
||||
|
||||
txn_payload = {
|
||||
'action': action,
|
||||
'fundingSourceType': 'CREDIT_DEBIT',
|
||||
'amounts': {
|
||||
'transactionAmount': minor_amount,
|
||||
'orderAmount': minor_amount,
|
||||
@@ -525,11 +546,7 @@ class PoyntController(http.Controller):
|
||||
'currency': tx_sudo.currency_id.name,
|
||||
},
|
||||
'fundingSource': funding_source,
|
||||
'context': {
|
||||
'source': 'WEB',
|
||||
'sourceApp': 'odoo.fusion_poynt',
|
||||
'transactionInstruction': 'ONLINE_AUTH_REQUIRED',
|
||||
},
|
||||
'context': context,
|
||||
'notes': reference,
|
||||
}
|
||||
|
||||
@@ -539,7 +556,7 @@ class PoyntController(http.Controller):
|
||||
'type': 'POYNT_ORDER',
|
||||
}]
|
||||
|
||||
result = tx_sudo.provider_id._poynt_make_request(
|
||||
result = provider._poynt_make_request(
|
||||
'POST', 'transactions', payload=txn_payload,
|
||||
)
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@ class AccountMove(models.Model):
|
||||
string="Has Poynt Receipt",
|
||||
compute='_compute_has_poynt_receipt',
|
||||
)
|
||||
poynt_transaction_count = fields.Integer(
|
||||
string="Poynt Transactions",
|
||||
compute='_compute_poynt_transaction_count',
|
||||
)
|
||||
|
||||
@api.depends('reversal_move_ids')
|
||||
def _compute_poynt_refund_count(self):
|
||||
@@ -38,6 +42,33 @@ class AccountMove(models.Model):
|
||||
for move in self:
|
||||
move.has_poynt_receipt = bool(move._get_poynt_transaction_for_receipt())
|
||||
|
||||
def _compute_poynt_transaction_count(self):
|
||||
for move in self:
|
||||
move.poynt_transaction_count = self.env['payment.transaction'].sudo().search_count([
|
||||
('invoice_ids', 'in', move.id),
|
||||
('provider_code', '=', 'poynt'),
|
||||
])
|
||||
|
||||
def action_view_poynt_transactions(self):
|
||||
"""Open payment transactions linked to this invoice/credit note."""
|
||||
self.ensure_one()
|
||||
transactions = self.env['payment.transaction'].sudo().search([
|
||||
('invoice_ids', 'in', self.id),
|
||||
('provider_code', '=', 'poynt'),
|
||||
])
|
||||
action = {
|
||||
'name': _("Poynt Transactions"),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'payment.transaction',
|
||||
'domain': [('id', 'in', transactions.ids)],
|
||||
}
|
||||
if len(transactions) == 1:
|
||||
action['view_mode'] = 'form'
|
||||
action['res_id'] = transactions.id
|
||||
else:
|
||||
action['view_mode'] = 'list,form'
|
||||
return action
|
||||
|
||||
def action_view_poynt_refunds(self):
|
||||
"""Open the credit notes linked to this invoice that were refunded via Poynt."""
|
||||
self.ensure_one()
|
||||
|
||||
@@ -58,6 +58,8 @@ class PaymentTransaction(models.Model):
|
||||
|
||||
For direct (online) payments we create a Poynt order upfront and return
|
||||
identifiers plus the return URL so the frontend JS can complete the flow.
|
||||
The actual transaction is created later when the frontend sends card
|
||||
details via the /payment/poynt/process_card route.
|
||||
"""
|
||||
if self.provider_code != 'poynt':
|
||||
return super()._get_specific_processing_values(processing_values)
|
||||
@@ -65,7 +67,7 @@ class PaymentTransaction(models.Model):
|
||||
if self.operation == 'online_token':
|
||||
return {}
|
||||
|
||||
poynt_data = self._poynt_create_order_and_authorize()
|
||||
order_data = self._poynt_create_order()
|
||||
|
||||
provider = self._get_provider_sudo()
|
||||
base_url = provider.get_base_url()
|
||||
@@ -75,8 +77,7 @@ class PaymentTransaction(models.Model):
|
||||
)
|
||||
|
||||
return {
|
||||
'poynt_order_id': poynt_data.get('order_id', ''),
|
||||
'poynt_transaction_id': poynt_data.get('transaction_id', ''),
|
||||
'poynt_order_id': order_data.get('order_id', ''),
|
||||
'return_url': return_url,
|
||||
'business_id': provider.poynt_business_id,
|
||||
'is_test': provider.state == 'test',
|
||||
@@ -108,6 +109,33 @@ class PaymentTransaction(models.Model):
|
||||
return
|
||||
self._process('poynt', payment_data)
|
||||
|
||||
def _poynt_create_order(self):
|
||||
"""Create a Poynt order without a transaction.
|
||||
|
||||
Used by the portal payment flow where card details are collected
|
||||
on the frontend and the transaction is created separately via
|
||||
the /payment/poynt/process_card route.
|
||||
|
||||
:return: Dict with order_id.
|
||||
:rtype: dict
|
||||
"""
|
||||
try:
|
||||
provider = self._get_provider_sudo()
|
||||
order_payload = poynt_utils.build_order_payload(
|
||||
self.reference, self.amount, self.currency_id,
|
||||
business_id=provider.poynt_business_id,
|
||||
store_id=provider.poynt_store_id or '',
|
||||
)
|
||||
order_result = provider._poynt_make_request(
|
||||
'POST', 'orders', payload=order_payload,
|
||||
)
|
||||
order_id = order_result.get('id', '')
|
||||
self.poynt_order_id = order_id
|
||||
return {'order_id': order_id}
|
||||
except ValidationError as e:
|
||||
self._set_error(str(e))
|
||||
return {}
|
||||
|
||||
def _poynt_create_order_and_authorize(self):
|
||||
"""Create a Poynt order and authorize the transaction.
|
||||
|
||||
@@ -383,6 +411,7 @@ class PaymentTransaction(models.Model):
|
||||
try:
|
||||
refund_payload = {
|
||||
'action': 'REFUND',
|
||||
'fundingSourceType': 'CREDIT_DEBIT',
|
||||
'parentId': parent_txn_id,
|
||||
'fundingSource': {
|
||||
'type': 'CREDIT_DEBIT',
|
||||
@@ -426,6 +455,7 @@ class PaymentTransaction(models.Model):
|
||||
try:
|
||||
capture_payload = {
|
||||
'action': 'CAPTURE',
|
||||
'fundingSourceType': 'CREDIT_DEBIT',
|
||||
'parentId': source_tx.provider_reference,
|
||||
'amounts': {
|
||||
'transactionAmount': minor_amount,
|
||||
@@ -817,6 +847,7 @@ class PaymentTransaction(models.Model):
|
||||
self._poynt_store_receipt_data(payment_data)
|
||||
self._poynt_attach_receipt_pdf()
|
||||
self._poynt_attach_poynt_receipt()
|
||||
self._poynt_auto_send_invoice_and_receipt()
|
||||
except Exception:
|
||||
_logger.exception(
|
||||
"Receipt generation failed for transaction %s", self.reference,
|
||||
@@ -925,6 +956,64 @@ class PaymentTransaction(models.Model):
|
||||
'mimetype': 'text/html',
|
||||
})
|
||||
|
||||
def _poynt_auto_send_invoice_and_receipt(self):
|
||||
"""Automatically email the invoice and payment receipt to the customer
|
||||
after a successful payment.
|
||||
|
||||
1. Sends the invoice via the standard Odoo invoice email template.
|
||||
2. Sends the Poynt payment receipt email with the PDF attached.
|
||||
|
||||
Best-effort: failures are logged but never block the payment flow.
|
||||
"""
|
||||
self.ensure_one()
|
||||
invoice = self.invoice_ids[:1]
|
||||
partner = self.partner_id
|
||||
|
||||
if not partner.email:
|
||||
_logger.info(
|
||||
"Skipping auto-send for %s: partner %s has no email.",
|
||||
self.reference, partner.display_name,
|
||||
)
|
||||
return
|
||||
|
||||
# 1. Send the invoice PDF
|
||||
if invoice and invoice.state == 'posted':
|
||||
try:
|
||||
inv_template = self.env.ref(
|
||||
'account.email_template_edi_invoice',
|
||||
raise_if_not_found=False,
|
||||
)
|
||||
if inv_template:
|
||||
inv_template.sudo().send_mail(
|
||||
invoice.id, force_send=True,
|
||||
)
|
||||
invoice.sudo().write({'is_move_sent': True})
|
||||
_logger.info(
|
||||
"Auto-sent invoice %s to %s",
|
||||
invoice.name, partner.email,
|
||||
)
|
||||
except Exception:
|
||||
_logger.exception(
|
||||
"Failed to auto-send invoice %s", invoice.name,
|
||||
)
|
||||
|
||||
# 2. Send the payment receipt
|
||||
try:
|
||||
receipt_template = self.env.ref(
|
||||
'fusion_poynt.mail_template_poynt_receipt',
|
||||
raise_if_not_found=False,
|
||||
)
|
||||
if receipt_template:
|
||||
receipt_template.sudo().send_mail(self.id, force_send=True)
|
||||
_logger.info(
|
||||
"Auto-sent payment receipt for %s to %s",
|
||||
self.reference, partner.email,
|
||||
)
|
||||
except Exception:
|
||||
_logger.exception(
|
||||
"Failed to auto-send receipt for %s", self.reference,
|
||||
)
|
||||
|
||||
def _get_poynt_receipt_values(self):
|
||||
"""Parse the stored receipt JSON for use in QWeb templates.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import logging
|
||||
|
||||
from odoo import _, models
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -11,6 +11,37 @@ _logger = logging.getLogger(__name__)
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
poynt_transaction_count = fields.Integer(
|
||||
string="Poynt Transactions",
|
||||
compute='_compute_poynt_transaction_count',
|
||||
)
|
||||
|
||||
def _compute_poynt_transaction_count(self):
|
||||
for order in self:
|
||||
order.poynt_transaction_count = self.env['payment.transaction'].sudo().search_count([
|
||||
('sale_order_ids', 'in', order.id),
|
||||
('provider_code', '=', 'poynt'),
|
||||
])
|
||||
|
||||
def action_view_poynt_transactions(self):
|
||||
self.ensure_one()
|
||||
transactions = self.env['payment.transaction'].sudo().search([
|
||||
('sale_order_ids', 'in', self.id),
|
||||
('provider_code', '=', 'poynt'),
|
||||
])
|
||||
action = {
|
||||
'name': _("Poynt Transactions"),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'payment.transaction',
|
||||
'domain': [('id', 'in', transactions.ids)],
|
||||
}
|
||||
if len(transactions) == 1:
|
||||
action['view_mode'] = 'form'
|
||||
action['res_id'] = transactions.id
|
||||
else:
|
||||
action['view_mode'] = 'list,form'
|
||||
return action
|
||||
|
||||
def action_poynt_collect_payment(self):
|
||||
"""Create an invoice (if needed) and open the Poynt payment wizard.
|
||||
|
||||
|
||||
@@ -45,6 +45,22 @@ patch(PaymentForm.prototype, {
|
||||
this._setupCardFormatting(poyntContainer);
|
||||
this._setupTerminalToggle(poyntContainer);
|
||||
this._setupSurcharge(poyntContainer);
|
||||
this._prefillBillingAddress(poyntContainer);
|
||||
},
|
||||
|
||||
_prefillBillingAddress(container) {
|
||||
const billing = this.poyntFormData.billing_details;
|
||||
if (!billing || !billing.address) return;
|
||||
const addr = billing.address;
|
||||
const setVal = (id, val) => {
|
||||
const el = container.querySelector(id);
|
||||
if (el && val) el.value = val;
|
||||
};
|
||||
setVal('#poynt_billing_address', addr.line1);
|
||||
setVal('#poynt_billing_city', addr.city);
|
||||
setVal('#poynt_billing_state', addr.state);
|
||||
setVal('#poynt_billing_zip', addr.postal_code);
|
||||
setVal('#poynt_billing_country', addr.country);
|
||||
},
|
||||
|
||||
_detectCardBrand(number) {
|
||||
@@ -317,6 +333,36 @@ patch(PaymentForm.prototype, {
|
||||
return checked ? checked.value : 'other';
|
||||
},
|
||||
|
||||
_showProcessingOverlay(container) {
|
||||
const overlay = container.querySelector('.o_poynt_processing_overlay');
|
||||
if (overlay) {
|
||||
// Hide all form field sections
|
||||
Array.from(container.children).forEach(child => {
|
||||
if (!child.classList.contains('o_poynt_processing_overlay')) {
|
||||
child.style.display = 'none';
|
||||
}
|
||||
});
|
||||
overlay.style.display = 'block';
|
||||
}
|
||||
},
|
||||
|
||||
_hideProcessingOverlay(container) {
|
||||
const overlay = container.querySelector('.o_poynt_processing_overlay');
|
||||
if (overlay) {
|
||||
overlay.style.display = 'none';
|
||||
Array.from(container.children).forEach(child => {
|
||||
if (!child.classList.contains('o_poynt_processing_overlay')) {
|
||||
child.style.display = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_updateProcessingMessage(container, message) {
|
||||
const msgEl = container.querySelector('.o_poynt_processing_message');
|
||||
if (msgEl) msgEl.textContent = message;
|
||||
},
|
||||
|
||||
async _processCardPayment(processingValues, inlineForm) {
|
||||
const cardNumber = inlineForm.querySelector('#poynt_card_number').value.replace(/\D/g, '');
|
||||
const expiry = inlineForm.querySelector('#poynt_expiry').value;
|
||||
@@ -328,6 +374,13 @@ patch(PaymentForm.prototype, {
|
||||
|
||||
const [expMonth, expYear] = expiry.split('/').map(Number);
|
||||
|
||||
const formContainer = inlineForm.closest('.o_poynt_payment_form')
|
||||
|| inlineForm.querySelector('.o_poynt_payment_form')
|
||||
|| inlineForm;
|
||||
|
||||
// Show processing animation
|
||||
this._showProcessingOverlay(formContainer);
|
||||
|
||||
try {
|
||||
const result = await rpc('/payment/poynt/process_card', {
|
||||
reference: processingValues.reference,
|
||||
@@ -338,9 +391,15 @@ patch(PaymentForm.prototype, {
|
||||
cvv: cvv,
|
||||
cardholder_name: cardholder,
|
||||
card_type: cardType,
|
||||
billing_address: inlineForm.querySelector('#poynt_billing_address')?.value || '',
|
||||
billing_city: inlineForm.querySelector('#poynt_billing_city')?.value || '',
|
||||
billing_state: inlineForm.querySelector('#poynt_billing_state')?.value || '',
|
||||
billing_zip: inlineForm.querySelector('#poynt_billing_zip')?.value || '',
|
||||
billing_country: inlineForm.querySelector('#poynt_billing_country')?.value || '',
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
this._hideProcessingOverlay(formContainer);
|
||||
this._displayErrorDialog(
|
||||
_t("Payment Failed"),
|
||||
result.error,
|
||||
@@ -349,8 +408,10 @@ patch(PaymentForm.prototype, {
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateProcessingMessage(formContainer, _t("Payment successful! Redirecting..."));
|
||||
window.location.href = processingValues.return_url;
|
||||
} catch (error) {
|
||||
this._hideProcessingOverlay(formContainer);
|
||||
this._displayErrorDialog(
|
||||
_t("Payment Processing Error"),
|
||||
error.message || _t("An unexpected error occurred."),
|
||||
|
||||
@@ -269,6 +269,7 @@ def build_transaction_payload(
|
||||
|
||||
payload = {
|
||||
'action': action,
|
||||
'fundingSourceType': 'CREDIT_DEBIT',
|
||||
'amounts': {
|
||||
'transactionAmount': minor_amount,
|
||||
'orderAmount': minor_amount,
|
||||
@@ -318,6 +319,7 @@ def build_token_charge_payload(
|
||||
|
||||
payload = {
|
||||
'action': action,
|
||||
'fundingSourceType': 'CREDIT_DEBIT',
|
||||
'context': context,
|
||||
'amounts': {
|
||||
'transactionAmount': minor_amount,
|
||||
|
||||
@@ -8,8 +8,15 @@
|
||||
<field name="priority">60</field>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<!-- Poynt Refund smart button on invoices -->
|
||||
<!-- Poynt Transaction smart button -->
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="action_view_poynt_transactions"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-credit-card"
|
||||
invisible="poynt_transaction_count == 0">
|
||||
<field name="poynt_transaction_count" widget="statinfo" string="Poynt Payments"/>
|
||||
</button>
|
||||
<button name="action_view_poynt_refunds"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
|
||||
@@ -62,6 +62,51 @@
|
||||
autocomplete="cc-name"/>
|
||||
</div>
|
||||
|
||||
<!-- Billing address -->
|
||||
<div class="mb-3 o_poynt_billing_section">
|
||||
<label class="form-label fw-bold">Billing Address</label>
|
||||
<div class="mb-2">
|
||||
<input type="text" class="form-control"
|
||||
id="poynt_billing_address"
|
||||
name="billing_address"
|
||||
placeholder="Street Address"
|
||||
autocomplete="billing street-address"/>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control"
|
||||
id="poynt_billing_city"
|
||||
name="billing_city"
|
||||
placeholder="City"
|
||||
autocomplete="billing address-level2"/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control"
|
||||
id="poynt_billing_state"
|
||||
name="billing_state"
|
||||
placeholder="Province / State"
|
||||
autocomplete="billing address-level1"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control"
|
||||
id="poynt_billing_zip"
|
||||
name="billing_zip"
|
||||
placeholder="Postal Code"
|
||||
autocomplete="billing postal-code"/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control"
|
||||
id="poynt_billing_country"
|
||||
name="billing_country"
|
||||
placeholder="Country Code (CA, US)"
|
||||
maxlength="2"
|
||||
autocomplete="billing country"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card type selector (for terminal payments where card brand cannot be auto-detected) -->
|
||||
<div class="mb-3 o_poynt_card_type_section" style="display:none;">
|
||||
<label class="form-label">Card Type</label>
|
||||
@@ -117,6 +162,17 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Processing overlay (hidden until payment is submitted) -->
|
||||
<div class="o_poynt_processing_overlay" style="display:none;">
|
||||
<div class="text-center p-4">
|
||||
<div class="spinner-border text-primary mb-3" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<h5 class="o_poynt_processing_message">Processing your payment...</h5>
|
||||
<p class="text-muted">Please do not close this page.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -28,10 +28,16 @@
|
||||
confirm="Are you sure you want to void this transaction? This reverses the payment before settlement and cannot be undone. Only works same-day before closeout (6 PM)."/>
|
||||
</xpath>
|
||||
|
||||
<!-- Add voided fields to the form sheet -->
|
||||
<!-- Add Poynt fields and linked records after provider_reference -->
|
||||
<xpath expr="//field[@name='provider_reference']" position="after">
|
||||
<field name="poynt_voided" invisible="1"/>
|
||||
<field name="poynt_void_date" invisible="not poynt_voided"/>
|
||||
<field name="poynt_order_id" invisible="provider_code != 'poynt'" readonly="1"/>
|
||||
<field name="poynt_transaction_id" invisible="provider_code != 'poynt'" readonly="1"/>
|
||||
<field name="sale_order_ids" widget="many2many_tags" readonly="1"
|
||||
string="Sale Orders"/>
|
||||
<field name="invoice_ids" widget="many2many_tags" readonly="1"
|
||||
string="Invoices"/>
|
||||
</xpath>
|
||||
|
||||
</field>
|
||||
|
||||
@@ -7,6 +7,18 @@
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="priority">60</field>
|
||||
<field name="arch" type="xml">
|
||||
<!-- Transaction count smart button -->
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="action_view_poynt_transactions"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-credit-card"
|
||||
invisible="poynt_transaction_count == 0">
|
||||
<field name="poynt_transaction_count" widget="statinfo" string="Poynt Payments"/>
|
||||
</button>
|
||||
</xpath>
|
||||
|
||||
<!-- Collect Payment action button -->
|
||||
<xpath expr="//button[@id='create_invoice']" position="after">
|
||||
<button name="action_poynt_collect_payment"
|
||||
string="Collect Payment"
|
||||
|
||||
@@ -409,6 +409,7 @@ class PoyntPaymentWizard(models.TransientModel):
|
||||
|
||||
txn_payload = {
|
||||
'action': action,
|
||||
'fundingSourceType': 'CREDIT_DEBIT',
|
||||
'amounts': {
|
||||
'transactionAmount': minor_amount,
|
||||
'orderAmount': minor_amount,
|
||||
|
||||
@@ -314,6 +314,7 @@ class PoyntRefundWizard(models.TransientModel):
|
||||
|
||||
refund_payload = {
|
||||
'action': 'REFUND',
|
||||
'fundingSourceType': 'CREDIT_DEBIT',
|
||||
'parentId': parent_txn_id,
|
||||
'fundingSource': {
|
||||
'type': 'CREDIT_DEBIT',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_renewal_log_user,rental.renewal.log.user,model_rental_renewal_log,sales_team.group_sale_salesman,1,0,0,0
|
||||
access_renewal_log_user,rental.renewal.log.user,model_rental_renewal_log,sales_team.group_sale_salesman,1,1,1,0
|
||||
access_renewal_log_manager,rental.renewal.log.manager,model_rental_renewal_log,fusion_rental.group_rental_manager,1,1,1,1
|
||||
access_cancellation_request_user,rental.cancellation.request.user,model_rental_cancellation_request,sales_team.group_sale_salesman,1,1,1,0
|
||||
access_cancellation_request_manager,rental.cancellation.request.manager,model_rental_cancellation_request,fusion_rental.group_rental_manager,1,1,1,1
|
||||
|
||||
|
Reference in New Issue
Block a user