foodbot-cart-calculations 1.0.62 → 1.0.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/functions/taxCalculation.js +191 -3
- package/index.js +3 -3
- package/package.json +1 -1
- package/response.json +3441 -459
|
@@ -84,9 +84,9 @@ function calculateTax2(cart, texSettings, taxType) {
|
|
|
84
84
|
}, 300)
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
calculateItemWiseSplit(cart).then((cart) => {
|
|
87
|
+
// calculateItemWiseSplit(cart).then((cart) => {
|
|
88
88
|
resolve(cart);
|
|
89
|
-
});
|
|
89
|
+
// });
|
|
90
90
|
}
|
|
91
91
|
});
|
|
92
92
|
} catch (error) {
|
|
@@ -806,4 +806,192 @@ async function calculateItemWiseSplit(cart, itemWiseItems) {
|
|
|
806
806
|
});
|
|
807
807
|
}
|
|
808
808
|
|
|
809
|
-
|
|
809
|
+
// calculateHalfSplit.js
|
|
810
|
+
/**
|
|
811
|
+
* Calculate half-split (or N-equal split for unpaid customers) with rounding adjustments.
|
|
812
|
+
*
|
|
813
|
+
* Parameters:
|
|
814
|
+
* - cart: object containing order, split_payments etc. (mutated and returned)
|
|
815
|
+
* - selectedMembers: (not used directly in calculation here, kept for parity with caller)
|
|
816
|
+
* - options: optional object {
|
|
817
|
+
* itemWiseItems, // array used to derive per-item tax/prices (falls back to cart.itemWiseItems)
|
|
818
|
+
* allItems, // template items for each split (falls back to cart.order.items or cart.items)
|
|
819
|
+
* halfSplitTaxPerPerson, // optional precomputed per-person tax (Number)
|
|
820
|
+
* halfSplitTotalPerPerson // optional precomputed per-person amount (Number)
|
|
821
|
+
* }
|
|
822
|
+
*
|
|
823
|
+
* Returns:
|
|
824
|
+
* - resolved Promise with updated cart
|
|
825
|
+
*/
|
|
826
|
+
async function calculateHalfSplit(cart, options = {}) {
|
|
827
|
+
return new Promise(async (resolve, reject) => {
|
|
828
|
+
try {
|
|
829
|
+
// Safe getters / defaults
|
|
830
|
+
const itemWiseItems = options.itemWiseItems || [];
|
|
831
|
+
const allItems = options.allItems || (cart && cart.items) || [];
|
|
832
|
+
const splits = cart.split_payments || [];
|
|
833
|
+
|
|
834
|
+
// Totals
|
|
835
|
+
const totalAmount = parseFloat((cart.after_discount) ?? 0) || 0;
|
|
836
|
+
const totalTax = parseFloat((cart.tax_amount) ?? 0) || 0;
|
|
837
|
+
|
|
838
|
+
// Already paid sums
|
|
839
|
+
const paidSplits = splits.filter((p) => p.paid_status);
|
|
840
|
+
const paidAmount = paidSplits.reduce((sum, p) => sum + (parseFloat(p.amount || '0') || 0), 0);
|
|
841
|
+
const paidTax = paidSplits.reduce((sum, p) => sum + (parseFloat(p.tax || '0') || 0), 0);
|
|
842
|
+
|
|
843
|
+
// Unpaid totals
|
|
844
|
+
const unpaidTotalAmount = totalAmount - paidAmount;
|
|
845
|
+
const unpaidTotalTax = totalTax - paidTax;
|
|
846
|
+
|
|
847
|
+
// Unpaid split count
|
|
848
|
+
const unpaidSplits = splits.filter((p) => !p.paid_status);
|
|
849
|
+
const unpaidCount = unpaidSplits.length || 1; // avoid division by zero
|
|
850
|
+
|
|
851
|
+
// If caller provided per-person values use them, otherwise compute equal split per unpaid person
|
|
852
|
+
let halfSplitTaxPerPerson = (typeof options.halfSplitTaxPerPerson == 'number')
|
|
853
|
+
? options.halfSplitTaxPerPerson
|
|
854
|
+
: unpaidTotalTax / unpaidCount;
|
|
855
|
+
|
|
856
|
+
let halfSplitTotalPerPerson = (typeof options.halfSplitTotalPerPerson == 'number')
|
|
857
|
+
? options.halfSplitTotalPerPerson
|
|
858
|
+
: unpaidTotalAmount / unpaidCount;
|
|
859
|
+
|
|
860
|
+
// Keep accumulators for rounding remainder
|
|
861
|
+
let accumulatedAmount = 0;
|
|
862
|
+
let accumulatedTax = 0;
|
|
863
|
+
let unpaidIndex = 0;
|
|
864
|
+
|
|
865
|
+
// For each split payment: assign items, compute item-level taxes & subtotal, then apply split rounding rules
|
|
866
|
+
for (let p of splits) {
|
|
867
|
+
if (!p.paid_status) {
|
|
868
|
+
const isLastUnpaid = unpaidIndex == unpaidCount - 1;
|
|
869
|
+
|
|
870
|
+
// clone items so we don't mutate shared object
|
|
871
|
+
p.items = JSON.parse(JSON.stringify(allItems));
|
|
872
|
+
|
|
873
|
+
// Recompute item-level tax/amount similar to your itemwise logic
|
|
874
|
+
let subtotal = 0;
|
|
875
|
+
let tax = 0;
|
|
876
|
+
|
|
877
|
+
for (let pi of p.items) {
|
|
878
|
+
const item = itemWiseItems.find((i) => i._temp_id == pi._temp_id);
|
|
879
|
+
if (!item) continue;
|
|
880
|
+
|
|
881
|
+
const qty = Number(pi.quantity || 0);
|
|
882
|
+
const price = Number(item.per_item_cost || 0);
|
|
883
|
+
const itemTaxTotal = Number(item.total_tax_amount || 0);
|
|
884
|
+
|
|
885
|
+
// quantity-wise tax array
|
|
886
|
+
const quantityWiseTaxArray = (item.tax_array || []).map((taxObj) => {
|
|
887
|
+
const unitBase = Number(taxObj.base_price || 0) / (Number(item.quantity) || 1);
|
|
888
|
+
const unitTaxAmount = Number(taxObj.tax_amount || 0) / (Number(item.quantity) || 1);
|
|
889
|
+
return {
|
|
890
|
+
...taxObj,
|
|
891
|
+
base_price: (unitBase * qty).toFixed(6),
|
|
892
|
+
tax_amount: (unitTaxAmount * qty).toFixed(6),
|
|
893
|
+
};
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
// modifiers
|
|
897
|
+
let modifierTaxArray = [];
|
|
898
|
+
const mods = item.item_modifiers || item.modifiers || [];
|
|
899
|
+
for (let m of mods) {
|
|
900
|
+
const mq = Number(m.quantity || 0) || 1;
|
|
901
|
+
const modTax = (m.tax_array || []).map((tx) => {
|
|
902
|
+
const unitBase = Number(tx.base_price || 0) / ((Number(item.quantity) || 1) * mq);
|
|
903
|
+
const unitTax = Number(tx.tax_amount || 0) / ((Number(item.quantity) || 1) * mq);
|
|
904
|
+
return {
|
|
905
|
+
...tx,
|
|
906
|
+
base_price: (unitBase * (mq * qty)).toFixed(6),
|
|
907
|
+
tax_amount: (unitTax * (mq * qty)).toFixed(6),
|
|
908
|
+
};
|
|
909
|
+
});
|
|
910
|
+
modifierTaxArray.push(...modTax);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// merge item-level taxes by tax_id
|
|
914
|
+
const mergedItemTaxMap = {};
|
|
915
|
+
for (let t of [...quantityWiseTaxArray, ...modifierTaxArray]) {
|
|
916
|
+
if (!mergedItemTaxMap[t.tax_id]) {
|
|
917
|
+
mergedItemTaxMap[t.tax_id] = { ...t, base_price: 0, tax_amount: 0 };
|
|
918
|
+
}
|
|
919
|
+
mergedItemTaxMap[t.tax_id].base_price += Number(t.base_price || 0);
|
|
920
|
+
mergedItemTaxMap[t.tax_id].tax_amount += Number(t.tax_amount || 0);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
pi.tax_array = Object.values(mergedItemTaxMap).map((i) => ({
|
|
924
|
+
...i,
|
|
925
|
+
base_price: Number(i.base_price).toFixed(6),
|
|
926
|
+
tax_amount: Number(i.tax_amount).toFixed(6),
|
|
927
|
+
}));
|
|
928
|
+
|
|
929
|
+
// subtotal and tax contribution for this item in this split
|
|
930
|
+
subtotal += price * qty;
|
|
931
|
+
tax += (itemTaxTotal / (Number(item.quantity) || 1)) * qty;
|
|
932
|
+
} // end items loop
|
|
933
|
+
|
|
934
|
+
// Merge tax_array across items for this split
|
|
935
|
+
const mergedTaxMap = {};
|
|
936
|
+
for (let pi of p.items) {
|
|
937
|
+
(pi.tax_array || []).forEach((t) => {
|
|
938
|
+
if (!mergedTaxMap[t.tax_id]) {
|
|
939
|
+
mergedTaxMap[t.tax_id] = { ...t, base_price: 0, tax_amount: 0 };
|
|
940
|
+
}
|
|
941
|
+
mergedTaxMap[t.tax_id].base_price += Number(t.base_price || 0);
|
|
942
|
+
mergedTaxMap[t.tax_id].tax_amount += Number(t.tax_amount || 0);
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
p.merge_tax_array = Object.values(mergedTaxMap).map((t) => ({
|
|
947
|
+
...t,
|
|
948
|
+
base_price: Number(t.base_price).toFixed(6),
|
|
949
|
+
tax_amount: Number(t.tax_amount).toFixed(6),
|
|
950
|
+
}));
|
|
951
|
+
|
|
952
|
+
// Apply equal split amounts with rounding adjustment:
|
|
953
|
+
if (isLastUnpaid) {
|
|
954
|
+
// last unpaid gets the remainder (unpaid totals minus accumulated assigned amounts)
|
|
955
|
+
// Use arithmetic with Number() and then format to 2 decimals for amount/tax
|
|
956
|
+
const remainingTax = (unpaidTotalTax - accumulatedTax);
|
|
957
|
+
const remainingAmount = (unpaidTotalAmount - accumulatedAmount);
|
|
958
|
+
|
|
959
|
+
p.tax = Number(remainingTax).toFixed(2);
|
|
960
|
+
p.amount = Number(remainingAmount).toFixed(2);
|
|
961
|
+
p.due = p.amount;
|
|
962
|
+
} else {
|
|
963
|
+
// Non-last unpaid: assign precomputed per-person values (rounded to 2 decimals)
|
|
964
|
+
const taxAmount = Number(Number(halfSplitTaxPerPerson).toFixed(2));
|
|
965
|
+
const dueAmount = Number(Number(halfSplitTotalPerPerson).toFixed(2));
|
|
966
|
+
|
|
967
|
+
p.tax = taxAmount.toFixed(2);
|
|
968
|
+
p.amount = dueAmount.toFixed(2);
|
|
969
|
+
p.due = dueAmount.toFixed(2);
|
|
970
|
+
|
|
971
|
+
accumulatedTax += taxAmount;
|
|
972
|
+
accumulatedAmount += dueAmount;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
unpaidIndex++;
|
|
976
|
+
} // end if unpaid
|
|
977
|
+
} // end for splits loop
|
|
978
|
+
|
|
979
|
+
// Attach updated splits back to cart (if different structure)
|
|
980
|
+
if (cart.split_payments) {
|
|
981
|
+
cart.split_payments = splits;
|
|
982
|
+
}
|
|
983
|
+
resolve(cart);
|
|
984
|
+
} catch (err) {
|
|
985
|
+
// bubble up so callers can handle
|
|
986
|
+
console.error("❌ Split Payment Calculation Failed:", err);
|
|
987
|
+
resolve({
|
|
988
|
+
'status': 'error',
|
|
989
|
+
'status_code': 500,
|
|
990
|
+
'message': 'Internal server error',
|
|
991
|
+
'error': error.stack,
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
module.exports = { calculateTax2, calculateItemWiseSplit, calculateHalfSplit }
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const calculation = require('./calculations');
|
|
2
|
-
const { calculateItemWiseSplit } = require('./functions/taxCalculation');
|
|
2
|
+
const { calculateItemWiseSplit, calculateHalfSplit } = require('./functions/taxCalculation');
|
|
3
3
|
// const fs = require('fs');
|
|
4
4
|
// const path = require('path')
|
|
5
5
|
|
|
@@ -76,7 +76,7 @@ async function calculateTax(inputJSON) {
|
|
|
76
76
|
})
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
let json = JSON.parse(fs.readFileSync('./sample.json', 'utf8'));
|
|
80
80
|
|
|
81
81
|
// calculateTax(json).then(res=>{
|
|
82
82
|
// // console.log(JSON.stringify(res))
|
|
@@ -114,4 +114,4 @@ async function calculateTax(inputJSON) {
|
|
|
114
114
|
// console.log(err)
|
|
115
115
|
// })
|
|
116
116
|
|
|
117
|
-
module.exports = { calculateTax , calculateItemWiseSplit}
|
|
117
|
+
module.exports = { calculateTax , calculateItemWiseSplit, calculateHalfSplit}
|
package/package.json
CHANGED