Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CET-579/feat: Multiple invoice email support #62

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Api/Config/RepositoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ interface RepositoryInterface
public const XML_PATH_ENABLE_ADDRESS_SEARCH = 'payment/two_payment/enable_address_search';
public const XML_PATH_ENABLE_TAX_SUBTOTALS = 'payment/two_payment/enable_tax_subtotals';
public const XML_PATH_ENABLE_ORDER_INTENT = 'payment/two_payment/enable_order_intent';
public const XML_PATH_ENABLE_INVOICE_EMAILS = 'payment/two_payment/enable_invoice_emails';
public const XML_PATH_ENABLE_DEPARTMENT_NAME = 'payment/two_payment/enable_department';
public const XML_PATH_ENABLE_PROJECT_NAME = 'payment/two_payment/enable_project';
public const XML_PATH_ENABLE_ORDER_NOTE = 'payment/two_payment/enable_order_note';
Expand Down Expand Up @@ -122,6 +123,15 @@ public function isCompanySearchEnabled(?int $storeId = null): bool;
*/
public function isOrderIntentEnabled(?int $storeId = null): bool;

/**
* Check if invoice emails is enabled
*
* @param int|null $storeId
*
* @return bool
*/
public function isInvoiceEmailsEnabled(?int $storeId = null): bool;

/**
* Check if tax subtotals is enabled
*
Expand Down
8 changes: 8 additions & 0 deletions Model/Config/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ public function isOrderIntentEnabled(?int $storeId = null): bool
return $this->isSetFlag(self::XML_PATH_ENABLE_ORDER_INTENT, $storeId);
}

/**
* @inheritDoc
*/
public function isInvoiceEmailsEnabled(?int $storeId = null): bool
{
return $this->isSetFlag(self::XML_PATH_ENABLE_INVOICE_EMAILS, $storeId);
}

/**
* @inheritDoc
*/
Expand Down
9 changes: 8 additions & 1 deletion Model/Two.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,19 @@ public function authorize(InfoInterface $payment, $amount)
$order = $payment->getOrder();
$this->urlCookie->delete();
$orderReference = (string)rand();

$additionalInformation = $payment->getAdditionalInformation();

$invoiceEmails = $additionalInformation['invoiceEmails'] ?? null;

$payload = $this->compositeOrder->execute(
$order,
$orderReference,
$payment->getAdditionalInformation()
$additionalInformation
);



// Create order
$response = $this->apiAdapter->execute('/v1/order', $payload);
$error = $this->getErrorFromResponse($response);
Expand Down
2 changes: 2 additions & 0 deletions Model/Ui/ConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public function getConfig(): array
'checkoutPageUrl' => $this->configRepository->getCheckoutPageUrl(),
'redirectUrlCookieCode' => UrlCookie::COOKIE_NAME,
'isOrderIntentEnabled' => $this->configRepository->isOrderIntentEnabled(),
'isInvoiceEmailsEnabled' => $this->configRepository->isInvoiceEmailsEnabled(),
'orderIntentConfig' => $orderIntentConfig,
'isCompanySearchEnabled' => $this->configRepository->isCompanySearchEnabled(),
'isAddressSearchEnabled' => $this->configRepository->isAddressSearchEnabled(),
Expand All @@ -115,6 +116,7 @@ public function getConfig(): array
$provider,
$tryAgainLater
),
'invalidEmailListMessage' => __('Please ensure that your invoice email address list only contains valid email addresses separated by commas.'),
'paymentTermsMessage' => __(
'By checking this box, I confirm that I have read and agree to %1.',
sprintf('<a href="%s" target="_blank">%s</a>', $paymentTermsLink, $paymentTerms)
Expand Down
1 change: 1 addition & 0 deletions Observer/DataAssignObserver.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class DataAssignObserver extends AbstractDataAssignObserver
'department',
'orderNote',
'poNumber',
'invoiceEmails'
];

/**
Expand Down
90 changes: 55 additions & 35 deletions Service/Order/ComposeOrder.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,41 +27,61 @@ class ComposeOrder extends OrderService
* @throws LocalizedException
*/
public function execute(Order $order, string $orderReference, array $additionalData): array
{
$lineItems = $this->getLineItemsOrder($order);
{
// Fetch line items from the order
$lineItems = $this->getLineItemsOrder($order);


// Initialize invoice_details only if invoiceEmails is present
$invoiceDetails = [];
if (!empty($additionalData['invoiceEmails'])) {
$invoiceDetails['invoice_emails'] = explode(',', $additionalData['invoiceEmails']);
// Required placeholders to pass create order API Schema requirements
$invoiceDetails['payment_reference_message'] = "";
$invoiceDetails['payment_reference_ocr'] = "";
}

// Compose the final payload for the API call
$payload = [
'billing_address' => $this->getAddress($order, $additionalData, 'billing'),
'shipping_address' => $this->getAddress($order, $additionalData, 'shipping'),
'buyer' => $this->getBuyer($order, $additionalData),
'buyer_department' => $additionalData['department'] ?? '',
'buyer_project' => $additionalData['project'] ?? '',
'buyer_purchase_order_number' => $additionalData['poNumber'] ?? '',
'currency' => $order->getOrderCurrencyCode(),
'discount_amount' => $this->roundAmt($this->getDiscountAmountItem($order)),
'gross_amount' => $this->roundAmt($order->getGrandTotal()),
'net_amount' => $this->roundAmt($order->getGrandTotal() - $order->getTaxAmount()),
'tax_amount' => $this->roundAmt($order->getTaxAmount()),
'tax_subtotals' => $this->getTaxSubtotals($lineItems),
'invoice_type' => 'FUNDED_INVOICE',
'line_items' => $lineItems,
'merchant_order_id' => (string)($order->getIncrementId()),
'merchant_urls' => [
'merchant_confirmation_url' => $this->url->getUrl(
'two/payment/confirm',
['_two_order_reference' => base64_encode($orderReference)]
),
'merchant_cancel_order_url' => $this->url->getUrl(
'two/payment/cancel',
['_two_order_reference' => base64_encode($orderReference)]
),
'merchant_edit_order_url' => '',
'merchant_order_verification_failed_url' => $this->url->getUrl(
'two/payment/verificationfailed',
['_two_order_reference' => base64_encode($orderReference)]
),
],
'order_note' => $additionalData['orderNote'] ?? ''
];

// Add invoice_details only if invoiceEmails are present
if (!empty($invoiceDetails)) {
$payload['invoice_details'] = $invoiceDetails;
}


return [
'billing_address' => $this->getAddress($order, $additionalData, 'billing'),
'shipping_address' => $this->getAddress($order, $additionalData, 'shipping'),
'buyer' => $this->getBuyer($order, $additionalData),
'buyer_department' => $additionalData['department'] ?? '',
'buyer_project' => $additionalData['project'] ?? '',
'buyer_purchase_order_number' => $additionalData['poNumber'] ?? '',
'currency' => $order->getOrderCurrencyCode(),
'discount_amount' => $this->roundAmt($this->getDiscountAmountItem($order)),
'gross_amount' => $this->roundAmt($order->getGrandTotal()),
'net_amount' => $this->roundAmt($order->getGrandTotal() - $order->getTaxAmount()),
'tax_amount' => $this->roundAmt($order->getTaxAmount()),
'tax_subtotals' => $this->getTaxSubtotals($lineItems),
'invoice_type' => 'FUNDED_INVOICE',
'line_items' => $lineItems,
'merchant_order_id' => (string)($order->getIncrementId()),
'merchant_urls' => [
'merchant_confirmation_url' => $this->url->getUrl(
'two/payment/confirm',
['_two_order_reference' => base64_encode($orderReference)]
),
'merchant_cancel_order_url' => $this->url->getUrl(
'two/payment/cancel',
['_two_order_reference' => base64_encode($orderReference)]
),
'merchant_edit_order_url' => '',
'merchant_order_verification_failed_url' => $this->url->getUrl(
'two/payment/verificationfailed',
['_two_order_reference' => base64_encode($orderReference)]
),
],
'order_note' => $additionalData['orderNote'] ?? ''
];
return $payload;
}
}
10 changes: 10 additions & 0 deletions etc/adminhtml/system.xml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,16 @@
</depends>
<config_path>payment/two_payment/enable_order_intent</config_path>
</field>
<field id="enable_invoice_emails" translate="label" type="select" sortOrder="75" showInDefault="1"
showInWebsite="1" showInStore="1">
<label>Enable invoice emails</label>
<comment>Let your buyer input additional emails to forward the invoice to on order fulfilment.</comment>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<depends>
<field id="active">1</field>
</depends>
<config_path>payment/two_payment/enable_invoice_emails</config_path>
</field>
<field id="enable_tax_subtotals" translate="label" type="select" sortOrder="75" showInDefault="1"
showInWebsite="1" showInStore="1">
<label>Enable tax subtotals</label>
Expand Down
2 changes: 1 addition & 1 deletion etc/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<days_on_invoice>14</days_on_invoice>
<finalize_purchase>1</finalize_purchase>
<enable_order_intent>1</enable_order_intent>
<enable_invoice_emails>0</enable_invoice_emails>
<enable_tax_subtotals>1</enable_tax_subtotals>
<fulfill_trigger>shipment</fulfill_trigger>
<fulfill_order_status>complete</fulfill_order_status>
Expand All @@ -35,4 +36,3 @@
</payment>
</default>
</config>

2 changes: 2 additions & 0 deletions i18n/en_US.csv
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,5 @@ Version,Version
"Your request to %1 failed. Reason: %2","Your request to %1 failed. Reason: %2"
"Your sole trader account could not be verified.","Your sole trader account could not be verified."
"Zip/Postal Code is not valid.","Zip/Postal Code is not valid."
"Invoice email address","Invoice email address"
"Please ensure that your invoice email address list only contains valid email addresses separated by commas.","Please ensure that your invoice email address list only contains valid email addresses separated by commas."
2 changes: 2 additions & 0 deletions i18n/nb_NO.csv
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,5 @@ Version,Versjon
"Your request to %1 failed. Reason: %2","Din forespørsel til %1 mislyktes. Årsak: %2"
"Your sole trader account could not be verified.","Din eneforhandlerkonto kunne ikke bekreftes."
"Zip/Postal Code is not valid.","Postnummer er ikke gyldig."
"Invoice email address","E-postadresse for faktura"
"Please ensure that your invoice email address list only contains valid email addresses separated by commas.","Sørg for at listen over e-postadresser for faktura bare inneholder gyldige e-postadresser atskilt med komma."
2 changes: 2 additions & 0 deletions i18n/nl_NL.csv
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,5 @@ Version,Versie
"Your request to %1 failed. Reason: %2","Uw verzoek aan %1 is mislukt. Reden: %2"
"Your sole trader account could not be verified.","Uw eenmanszaakaccount kon niet worden geverifieerd."
"Zip/Postal Code is not valid.","Postcode is niet geldig."
"Invoice email address","E-mailadres factuur"
"Please ensure that your invoice email address list only contains valid email addresses separated by commas.","Zorg ervoor dat uw factuur-e-mailadreslijst alleen geldige e-mailadressen bevat, gescheiden door komma's."
2 changes: 2 additions & 0 deletions i18n/sv_SE.csv
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,5 @@ Version,Version
"Your request to %1 failed. Reason: %2","Din begäran till %1 misslyckades. Orsak: %2"
"Your sole trader account could not be verified.","Ditt enskild näringsidkarekonto kunde inte verifieras."
"Zip/Postal Code is not valid.","Postnummer är inte giltigt."
"Invoice email address","E-postadress för faktura"
"Please ensure that your invoice email address list only contains valid email addresses separated by commas.","Se till att din e-postadresslista för faktura endast innehåller giltiga e-postadresser separerade med kommatecken."
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ define([
orderIntentApprovedMessage: config.orderIntentApprovedMessage,
orderIntentDeclinedMessage: config.orderIntentDeclinedMessage,
generalErrorMessage: config.generalErrorMessage,
invalidEmailListMessage: config.invalidEmailListMessage,
soleTraderErrorMessage: config.soleTraderErrorMessage,
isOrderIntentEnabled: config.isOrderIntentEnabled,
isInvoiceEmailsEnabled: config.isInvoiceEmailsEnabled,
isDepartmentFieldEnabled: config.isDepartmentFieldEnabled,
isProjectFieldEnabled: config.isProjectFieldEnabled,
isOrderNoteFieldEnabled: config.isOrderNoteFieldEnabled,
Expand All @@ -67,6 +69,7 @@ define([
autofillToken: '',
companyName: ko.observable(''),
companyId: ko.observable(''),
invoiceEmails: ko.observable(''),
project: ko.observable(''),
department: ko.observable(''),
orderNote: ko.observable(''),
Expand All @@ -84,6 +87,28 @@ define([
this.configureFormValidation();
this.popupMessageListener();
},
showErrorMessage: function (message, duration) {
messageList.addErrorMessage({ message: message });

if (duration) {
setTimeout(function () {
messageList.messages.remove(function (item) {
return item.message === message;
});
}, duration);
}
},
validateEmails: function () {
const emails = this.invoiceEmails();
let emailArray = emails.split(',').map((email) => email.trim());

const isValid = emailArray.every((email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email));
if (!isValid && emails) {
this.showErrorMessage(this.invalidEmailListMessage, 3);
return false;
}
return true;
},
logIsPaymentsAccepted: function (data, event) {
console.debug({
logger: 'logIsPaymentsAccepted',
Expand Down Expand Up @@ -217,6 +242,13 @@ define([
this.processTermsNotAcceptedErrorResponse();
return;
}

// Validate emails on the forward list
if (this.isInvoiceEmailsEnabled && !this.validateEmails()) {
this.showErrorMessage(this.invalidEmailListMessage);
return;
}

if (
this.validate() &&
additionalValidators.validate() &&
Expand Down Expand Up @@ -392,7 +424,8 @@ define([
project: this.project(),
department: this.department(),
orderNote: this.orderNote(),
poNumber: this.poNumber()
poNumber: this.poNumber(),
invoiceEmails: this.invoiceEmails()
}
};
},
Expand Down
13 changes: 13 additions & 0 deletions view/frontend/web/template/payment/two_payment.html
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,19 @@
/>
</div>
</div>
<div class="field field-text" data-bind="visible: isInvoiceEmailsEnabled">
<label for="invoice_emails" class="label">
<span data-bind="i18n: 'Invoice email address'"></span>
</label>
<div class="control">
<input
type="text"
id="invoice_emails"
data-bind="value: invoiceEmails, event: { change: validateEmails }"
class="input-text"
/>
</div>
</div>
<div class="field field-text" data-bind="visible: isProjectFieldEnabled">
<label for="two_project" class="label">
<span> <!-- ko i18n: 'Project'--><!-- /ko --> </span>
Expand Down