feat: Enhance software tool with country selection and tax calculation
- Added a helper function to generate country select options in software tool. - Updated user info modal and payment modal to use country dropdowns instead of text inputs. - Implemented tax calculation based on selected country in payment modal. - Improved software options loading behavior in debug mode. - Enhanced description formatting in payment modal. - Added log modal for equipment updates with a link to view logs. - Introduced a new countries settings file with tax rates for various countries. - Minor adjustments to various PHP files for better handling of equipment and payment processes.
This commit is contained in:
BIN
assets/.DS_Store
vendored
BIN
assets/.DS_Store
vendored
Binary file not shown.
@@ -1264,8 +1264,10 @@ function ioServer($api_call, $data){
|
||||
$http_status = curl_getinfo($curl) ?? '200';
|
||||
curl_close($curl);
|
||||
|
||||
if(debug){
|
||||
debuglog($date." - ioServer: URL=$url, HTTP Code=$http_status, Response=" . substr($resp, 0, 500) . (strlen($resp) > 500 ? '...' : ''));
|
||||
|
||||
if (debug) {
|
||||
$resp_log = $date . " - ioServer: URL=$url, HTTP Code= ". ($http_status['http_code'] ?? 'unknown') . ", Response=" . substr($resp, 0, 500) . (strlen($resp) > 500 ? '...' : '');
|
||||
debuglog(json_encode($resp_log));
|
||||
}
|
||||
|
||||
//Check If errorcode is returned
|
||||
@@ -1728,33 +1730,38 @@ function getPartnerID($str){
|
||||
// overview Indicators
|
||||
//------------------------------------------
|
||||
function overviewIndicators($warranty, $service, $sw_version, $sw_version_latest){
|
||||
include dirname(__FILE__,2).'/settings/settings_redirector.php';
|
||||
include dirname(__FILE__,2).'/settings/systemfirmware.php';
|
||||
$indicator ='';
|
||||
//In warranty
|
||||
if (!empty($warranty ) && $warranty > $warrantydate){
|
||||
$indicator .= '<span class="dot" style="background-color: #13b368;">W</span>';
|
||||
} else {
|
||||
$indicator .= '<span class="dot" style="background-color: #eb8a0d;">W</span>';
|
||||
}
|
||||
//Out of Service
|
||||
if (!empty($service) && $service < $servicedate){
|
||||
$indicator .= '<span class="dot" style="background-color: #eb8a0d;">S</span>';
|
||||
} else {
|
||||
$indicator .= '<span class="dot" style="background-color: #13b368;">S</span>';
|
||||
}
|
||||
|
||||
include dirname(__FILE__,2).'/settings/settings_redirector.php';
|
||||
include dirname(__FILE__,2).'/settings/systemfirmware.php';
|
||||
|
||||
$indicator ='';
|
||||
$current_date = date('Y-m-d');
|
||||
|
||||
//In warranty
|
||||
if (!empty($warranty ) && $warranty >= $current_date){
|
||||
$indicator .= '<span class="dot" style="background-color: #13b368;">W</span>';
|
||||
} else {
|
||||
$indicator .= '<span class="dot" style="background-color: #eb8a0d;">W</span>';
|
||||
}
|
||||
//Out of Service
|
||||
if (!empty($service) && $service >= $current_date){
|
||||
$indicator .= '<span class="dot" style="background-color: #13b368;">S</span>';
|
||||
} else {
|
||||
$indicator .= '<span class="dot" style="background-color: #eb8a0d;">S</span>';
|
||||
}
|
||||
|
||||
//Firmware
|
||||
if (isset($sw_version_latest)){
|
||||
if($sw_version_latest == 1){
|
||||
$indicator .= '<span class="dot" style="background-color: #13b368;">F</span>';
|
||||
if($sw_version_latest == 1){
|
||||
$indicator .= '<span class="dot" style="background-color: #13b368;">F</span>';
|
||||
}
|
||||
else {
|
||||
if ($sw_version == ''){
|
||||
$indicator .= '<span class="dot" style="background-color: #13b368;">F</span>';
|
||||
} else {
|
||||
if ($sw_version == ''){
|
||||
$indicator .= '<span class="dot" style="background-color: #13b368;">F</span>';
|
||||
} else {
|
||||
$indicator .= '<span class="dot" style="background-color: #eb8a0d;">F</span>';
|
||||
}
|
||||
$indicator .= '<span class="dot" style="background-color: #eb8a0d;">F</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $indicator;
|
||||
@@ -1783,11 +1790,12 @@ function warrantyStatus($input){
|
||||
}
|
||||
|
||||
$warranty_date_due ='<span class="status">Unknown</span>';
|
||||
|
||||
if (!empty($input) && $input < $warrantydate){
|
||||
$warranty_date_due = '<span class="status warranty_outdated">'.$warranty_outdated_text.'</span>';
|
||||
$current_date = date('Y-m-d');
|
||||
|
||||
if (!empty($input) && $input >= $current_date){
|
||||
$warranty_date_due = '<span class="">'.$warranty_recent.' ('.$input.')</span>';
|
||||
} else {
|
||||
$warranty_date_due = '<span class="">'.$warranty_recent.' ('.date('Y-m-d', strtotime($input. ' + 365 days')).')</span>';
|
||||
$warranty_date_due = '<span class="status warranty_outdated">'.$warranty_outdated_text.'</span>';
|
||||
}
|
||||
|
||||
return $warranty_date_due;
|
||||
@@ -1814,13 +1822,15 @@ function serviceStatus($input){
|
||||
else {
|
||||
include dirname(__FILE__,2).'/settings/translations/translations_US.php';
|
||||
}
|
||||
|
||||
|
||||
$current_date = date('Y-m-d');
|
||||
$service_date_due ='<span class="status">Unknown</span>';
|
||||
|
||||
if (!empty($input) && $input < $servicedate){
|
||||
$service_date_due = '<span class="status service_renewal">'.$service_renewal_text.'</span>';
|
||||
if (!empty($input) && $input >= $current_date){
|
||||
$service_date_due ='<span class="">'.$service_recent.' ('.$input.')</span>';
|
||||
} else {
|
||||
$service_date_due ='<span class="">'.$service_recent.' ('.date('Y-m-d', strtotime($input. ' + 365 days')).')</span>';
|
||||
$service_date_due = '<span class="status service_renewal">'.$service_renewal_text.'</span>';
|
||||
|
||||
}
|
||||
|
||||
return $service_date_due;
|
||||
@@ -2976,20 +2986,29 @@ function showlog($object,$objectID){
|
||||
$stmt->execute([$object,$objectID]);
|
||||
$changes = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$view = '<label for="productcode">Changelog</label>';
|
||||
foreach($changes as $change){
|
||||
|
||||
$object_value = $change['object_value'];
|
||||
|
||||
//UPDATE TO HUMANREADABLE STATUS
|
||||
if ($object == 'equipment' && $change['object_field'] == 'status'){
|
||||
$object_text = 'status'.$change['object_value'].'_text';
|
||||
$object_value = $$object_text;
|
||||
$view = '<div class="reg-fields">';
|
||||
if ($changes) {
|
||||
foreach ($changes as $change) {
|
||||
$object_value = $change['object_value'];
|
||||
// Human-readable status
|
||||
if ($object == 'equipment' && $change['object_field'] == 'status') {
|
||||
$object_text = 'status' . $change['object_value'] . '_text';
|
||||
if (isset($$object_text)) {
|
||||
$object_value = $$object_text;
|
||||
}
|
||||
}
|
||||
$entry = htmlspecialchars( $object_value . ' - ' . $change['created'] . ' - ' . $change['createdby']);
|
||||
$view .= ' <div class="reg-field">
|
||||
<label>'.$change['object_field'].'</label>
|
||||
<p>'.$entry.'</p>
|
||||
</div>';
|
||||
|
||||
}
|
||||
} else {
|
||||
$view .= '<div style="color:#888;font-size:13px;padding:8px;">No changelog entries found.</div>';
|
||||
}
|
||||
$view .= '<input id="name" type="text" value="'.$change['object_field'].' - '.$object_value.' - '.$change['created'].' - '.$change['createdby'].'" readonly>';
|
||||
}
|
||||
|
||||
return $view;
|
||||
$view .= '</div>';
|
||||
return $view;
|
||||
}
|
||||
|
||||
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@@ -5577,4 +5596,48 @@ function updateSoftwareLatestFlags($pdo, $version_id, $hw_version) {
|
||||
$stmt->execute([$version['rowID']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Generate Countries File from Taxes API +++++++++++++++++
|
||||
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
function generateCountriesFile($token){
|
||||
|
||||
//API call to get all taxes
|
||||
$api_url = '/v2/taxes';
|
||||
$response = ioAPIv2($api_url, '', $token);
|
||||
|
||||
if(!empty($response)){
|
||||
//decode the API response
|
||||
$taxes = json_decode($response, true);
|
||||
|
||||
if(!empty($taxes) && is_array($taxes)){
|
||||
//Build the countries array - id as key, with country name and tax rate
|
||||
$countries = [];
|
||||
foreach($taxes as $tax){
|
||||
$countries[$tax['id']] = [
|
||||
'country' => $tax['country'] ?? '',
|
||||
'taxes' => $tax['rate'] ?? 0
|
||||
];
|
||||
}
|
||||
|
||||
//Generate PHP file content
|
||||
$fileContent = "<?php\n";
|
||||
$fileContent .= "// Auto-generated countries file from taxes API\n";
|
||||
$fileContent .= "// Generated on: " . date('Y-m-d H:i:s') . "\n\n";
|
||||
$fileContent .= "\$countries = [\n";
|
||||
foreach($countries as $id => $data){
|
||||
$fileContent .= " " . $id . " => ['country' => '" . addslashes($data['country']) . "', 'taxes' => " . $data['taxes'] . "],\n";
|
||||
}
|
||||
$fileContent .= "];\n";
|
||||
|
||||
//Write to settings/countries.php
|
||||
$filePath = dirname(__FILE__, 2) . '/settings/countries.php';
|
||||
$result = file_put_contents($filePath, $fileContent);
|
||||
|
||||
return ($result !== false);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
BIN
assets/images/.DS_Store
vendored
BIN
assets/images/.DS_Store
vendored
Binary file not shown.
@@ -10,6 +10,26 @@ let deviceVersion = "";
|
||||
let deviceHwVersion = "";
|
||||
let selectedSoftwareUrl = "";
|
||||
|
||||
// Helper function to generate country select options
|
||||
function generateCountryOptions(selectedCountry = '') {
|
||||
if (typeof COUNTRIES === 'undefined' || !COUNTRIES) {
|
||||
return `<option value="">${typeof TRANS_COUNTRY !== 'undefined' ? TRANS_COUNTRY : 'Country'}</option>`;
|
||||
}
|
||||
|
||||
// Sort countries alphabetically
|
||||
const sortedCountries = Object.values(COUNTRIES).sort((a, b) => {
|
||||
return a.country.localeCompare(b.country);
|
||||
});
|
||||
|
||||
let options = '<option value="">Select country</option>';
|
||||
sortedCountries.forEach(data => {
|
||||
const selected = (selectedCountry === data.country) ? 'selected' : '';
|
||||
options += `<option value="${data.country}" ${selected}>${data.country}</option>`;
|
||||
});
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
// Serial port variables (port, writer, textEncoder, writableStreamClosed declared in PHP)
|
||||
let reader;
|
||||
let readableStreamClosed;
|
||||
@@ -528,8 +548,18 @@ async function fetchSoftwareOptions() {
|
||||
document.getElementById("softwareOptionsContainer").style.display = "block";
|
||||
progressBar("100", "Software options loaded", "#04AA6D");
|
||||
|
||||
// Show user info modal immediately
|
||||
showUserInfoModal();
|
||||
// Show user info modal immediately (skip in debug mode)
|
||||
if (typeof DEBUG === 'undefined' || !DEBUG) {
|
||||
showUserInfoModal();
|
||||
} else {
|
||||
// In debug mode, reveal software options immediately
|
||||
const softwareOptions = document.getElementById("softwareOptions");
|
||||
if (softwareOptions) {
|
||||
softwareOptions.style.filter = "none";
|
||||
softwareOptions.style.opacity = "1";
|
||||
softwareOptions.style.pointerEvents = "auto";
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
await logCommunication(`Software options error: ${error.message}`, 'error');
|
||||
@@ -665,7 +695,7 @@ function displaySoftwareOptions(options) {
|
||||
} else {
|
||||
priceText.innerHTML = isFree
|
||||
? 'Free'
|
||||
: `${option.currency || "€"} ${price.toFixed(2)}`;
|
||||
: `${option.currency || "€"} ${price.toFixed(2)} <small style="font-size: 12px; font-weight: 400; color: #888;">(excl. VAT)</small>`;
|
||||
}
|
||||
|
||||
priceSection.appendChild(priceText);
|
||||
@@ -777,7 +807,9 @@ function showUserInfoModal() {
|
||||
<input type="text" name="city" id="userInfoCity" required placeholder="${typeof TRANS_CITY !== 'undefined' ? TRANS_CITY : 'City'}" style="width: 100%; padding: 12px; border: 2px solid #ddd; border-radius: 6px; font-size: 14px; margin-bottom: 10px; transition: border 0.3s;" onfocus="this.style.borderColor='#04AA6D'" onblur="this.style.borderColor='#ddd'">
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||
<input type="text" name="postal" id="userInfoPostal" required placeholder="${typeof TRANS_POSTAL !== 'undefined' ? TRANS_POSTAL : 'Postal code'}" style="padding: 12px; border: 2px solid #ddd; border-radius: 6px; font-size: 14px; transition: border 0.3s;" onfocus="this.style.borderColor='#04AA6D'" onblur="this.style.borderColor='#ddd'">
|
||||
<input type="text" name="country" id="userInfoCountry" required placeholder="${typeof TRANS_COUNTRY !== 'undefined' ? TRANS_COUNTRY : 'Country'}" style="padding: 12px; border: 2px solid #ddd; border-radius: 6px; font-size: 14px; transition: border 0.3s;" onfocus="this.style.borderColor='#04AA6D'" onblur="this.style.borderColor='#ddd'">
|
||||
<select name="country" id="userInfoCountry" required style="padding: 12px; border: 2px solid #ddd; border-radius: 6px; font-size: 14px; transition: border 0.3s;" onfocus="this.style.borderColor='#04AA6D'" onblur="this.style.borderColor='#ddd'">
|
||||
${generateCountryOptions()}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -967,7 +999,9 @@ function showFreeInstallModal(option) {
|
||||
<input type="text" name="city" id="freeInstallCity" required placeholder="${typeof TRANS_CITY !== 'undefined' ? TRANS_CITY : 'City'}" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; margin-bottom: 10px;">
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||
<input type="text" name="postal" id="freeInstallPostal" required placeholder="${typeof TRANS_POSTAL !== 'undefined' ? TRANS_POSTAL : 'Postal code'}" style="padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||
<input type="text" name="country" id="freeInstallCountry" required placeholder="${typeof TRANS_COUNTRY !== 'undefined' ? TRANS_COUNTRY : 'Country'}" style="padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||
<select name="country" id="freeInstallCountry" required style="padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||
${generateCountryOptions()}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1045,6 +1079,17 @@ function showPaymentModal(option) {
|
||||
const price = parseFloat(option.price || 0);
|
||||
const currency = option.currency || "€";
|
||||
|
||||
// Format description as bullet points
|
||||
const formatDescription = (desc) => {
|
||||
if (!desc) return '';
|
||||
// Split by bullet points or newlines and filter out empty lines
|
||||
const lines = desc.split(/[•·\n]/).map(line => line.trim()).filter(line => line.length > 0);
|
||||
if (lines.length <= 1) return desc; // Return as-is if no multiple lines
|
||||
return '<ul style="margin: 0; padding-left: 20px; color: #666; font-size: 13px; line-height: 1.6;">' +
|
||||
lines.map(line => `<li>${line}</li>`).join('') +
|
||||
'</ul>';
|
||||
};
|
||||
|
||||
// Create modal overlay
|
||||
const modal = document.createElement("div");
|
||||
modal.id = "paymentModal";
|
||||
@@ -1082,9 +1127,20 @@ function showPaymentModal(option) {
|
||||
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
|
||||
<h4 style="margin: 0 0 10px 0; color: #333;">${option.name || "Software Update"}</h4>
|
||||
<p style="margin: 0 0 5px 0; color: #666;">Version: <strong>${option.version || "N/A"}</strong></p>
|
||||
<p style="margin: 0 0 15px 0; color: #666;">${option.description || ""}</p>
|
||||
<div style="font-size: 24px; font-weight: bold; color: #04AA6D;">
|
||||
${currency} ${price.toFixed(2)}
|
||||
<div style="margin: 0 0 15px 0;">${formatDescription(option.description)}</div>
|
||||
<div id="priceDisplay" style="font-size: 14px; color: #666;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
|
||||
<span>Price (excl. VAT):</span>
|
||||
<span style="font-weight: 600;">${currency} ${price.toFixed(2)}</span>
|
||||
</div>
|
||||
<div id="taxDisplay" style="display: flex; justify-content: space-between; margin-bottom: 5px;">
|
||||
<span>VAT:</span>
|
||||
<span style="font-weight: 600;">-</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; padding-top: 10px; border-top: 2px solid #ddd; margin-top: 10px;">
|
||||
<span style="font-weight: bold;">Total:</span>
|
||||
<span id="totalDisplay" style="font-size: 24px; font-weight: bold; color: #04AA6D;">${currency} ${price.toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1105,7 +1161,9 @@ function showPaymentModal(option) {
|
||||
<input type="text" name="city" id="paymentCity" required placeholder="${typeof TRANS_CITY !== 'undefined' ? TRANS_CITY : 'City'}" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; margin-bottom: 10px;">
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||
<input type="text" name="postal" id="paymentPostal" required placeholder="${typeof TRANS_POSTAL !== 'undefined' ? TRANS_POSTAL : 'Postal code'}" style="padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||
<input type="text" name="country" id="paymentCountry" required placeholder="${typeof TRANS_COUNTRY !== 'undefined' ? TRANS_COUNTRY : 'Country'}" style="padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||
<select name="country" id="paymentCountry" required style="padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||
${generateCountryOptions()}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1134,6 +1192,45 @@ function showPaymentModal(option) {
|
||||
modal.appendChild(modalContent);
|
||||
document.body.appendChild(modal);
|
||||
|
||||
// Function to calculate and update tax
|
||||
function updateTaxDisplay() {
|
||||
const selectedCountry = document.getElementById("paymentCountry").value;
|
||||
let taxRate = 0;
|
||||
|
||||
if (selectedCountry && typeof COUNTRIES !== 'undefined' && COUNTRIES) {
|
||||
const countryData = Object.values(COUNTRIES).find(c => c.country === selectedCountry);
|
||||
if (countryData) {
|
||||
taxRate = parseFloat(countryData.taxes) || 0;
|
||||
}
|
||||
}
|
||||
|
||||
const taxAmount = price * (taxRate / 100);
|
||||
const totalAmount = price + taxAmount;
|
||||
|
||||
// Update display
|
||||
const taxDisplay = document.getElementById("taxDisplay");
|
||||
const totalDisplay = document.getElementById("totalDisplay");
|
||||
|
||||
if (taxRate > 0) {
|
||||
taxDisplay.innerHTML = `
|
||||
<span>VAT (${taxRate}%):</span>
|
||||
<span style="font-weight: 600;">${currency} ${taxAmount.toFixed(2)}</span>
|
||||
`;
|
||||
} else {
|
||||
taxDisplay.innerHTML = `
|
||||
<span>VAT:</span>
|
||||
<span style="font-weight: 600;">-</span>
|
||||
`;
|
||||
}
|
||||
|
||||
totalDisplay.textContent = `${currency} ${totalAmount.toFixed(2)}`;
|
||||
|
||||
// Store tax info for form submission
|
||||
modal.taxRate = taxRate;
|
||||
modal.taxAmount = taxAmount;
|
||||
modal.totalAmount = totalAmount;
|
||||
}
|
||||
|
||||
// Prefill form with customer data from sessionStorage if available
|
||||
const savedCustomerData = sessionStorage.getItem('customerData');
|
||||
if (savedCustomerData) {
|
||||
@@ -1144,12 +1241,18 @@ function showPaymentModal(option) {
|
||||
if (customerData.address) document.getElementById("paymentAddress").value = customerData.address;
|
||||
if (customerData.city) document.getElementById("paymentCity").value = customerData.city;
|
||||
if (customerData.postal) document.getElementById("paymentPostal").value = customerData.postal;
|
||||
if (customerData.country) document.getElementById("paymentCountry").value = customerData.country;
|
||||
if (customerData.country) {
|
||||
document.getElementById("paymentCountry").value = customerData.country;
|
||||
updateTaxDisplay(); // Calculate tax based on saved country
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Error parsing saved customer data:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Add event listener to country select to update tax
|
||||
document.getElementById("paymentCountry").addEventListener('change', updateTaxDisplay);
|
||||
|
||||
// Close modal on cancel
|
||||
document.getElementById("cancelPayment").onclick = () => {
|
||||
document.body.removeChild(modal);
|
||||
@@ -1160,15 +1263,15 @@ function showPaymentModal(option) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target);
|
||||
const paymentMethod = formData.get("payment_method");
|
||||
|
||||
|
||||
// Auto-determine payment provider based on payment method
|
||||
let paymentProvider = 'mollie'; // default
|
||||
if (paymentMethod === 'paypal') {
|
||||
if (paymentMethod === '3') { // PayPal payment method ID
|
||||
paymentProvider = 'paypal';
|
||||
} else if (paymentMethod === 'credit_card' || paymentMethod === 'bank_transfer') {
|
||||
} else if (paymentMethod === '1' || paymentMethod === 'bank_transfer') { // Mollie (Credit Card) or Bank Transfer
|
||||
paymentProvider = 'mollie';
|
||||
}
|
||||
|
||||
|
||||
const paymentData = {
|
||||
name: formData.get("name"),
|
||||
email: formData.get("email"),
|
||||
@@ -1179,7 +1282,9 @@ function showPaymentModal(option) {
|
||||
payment_method: paymentMethod,
|
||||
payment_provider: paymentProvider,
|
||||
version_id: option.version_id,
|
||||
price: price,
|
||||
item_price: price, // Price without VAT
|
||||
tax_amount: modal.taxAmount || 0, // Tax amount
|
||||
payment_amount: modal.totalAmount || price, // Total price including tax
|
||||
currency: currency
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user