tango-app-api-payment-subscription 3.5.33 → 3.5.34
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/package.json
CHANGED
|
@@ -1804,27 +1804,27 @@ export async function bulkUpdateBillingGroups( req, res ) {
|
|
|
1804
1804
|
}
|
|
1805
1805
|
}
|
|
1806
1806
|
|
|
1807
|
-
// Sixth pass: cross-group
|
|
1808
|
-
// A store already assigned to a different billing group
|
|
1809
|
-
//
|
|
1807
|
+
// Sixth pass: cross-group MOVE detection with OTHER existing groups in the DB.
|
|
1808
|
+
// A store already assigned to a different billing group is treated as a
|
|
1809
|
+
// MOVE: it will be pulled out of its old group(s) during the write pass and
|
|
1810
|
+
// assigned to the group that claims it in this upload. (Cross-group
|
|
1811
|
+
// uniqueness WITHIN the upload is already enforced by the fourth pass.)
|
|
1810
1812
|
const idsInUpload = Array.from( groupedByName.values() ).map( ( e ) => e._id );
|
|
1813
|
+
// Map of old-group _id → [storeIds to pull]. Only groups NOT in this upload
|
|
1814
|
+
// need an explicit pull; groups in the upload get their stores[] fully
|
|
1815
|
+
// rewritten in the write pass, which naturally drops released stores.
|
|
1816
|
+
const storesToPullByGroupId = new Map();
|
|
1811
1817
|
if ( allStoreIds.length > 0 ) {
|
|
1812
|
-
const
|
|
1818
|
+
const otherGroupDocs = await billingService.find(
|
|
1813
1819
|
{ clientId, stores: { $in: allStoreIds }, _id: { $nin: idsInUpload } },
|
|
1814
1820
|
{ _id: 1, groupName: 1, stores: 1 },
|
|
1815
1821
|
);
|
|
1816
|
-
for ( const doc of
|
|
1817
|
-
const
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
errors.push( {
|
|
1823
|
-
rowNumber: claimingEntry.firstRowIndex + 2,
|
|
1824
|
-
groupName: claimingEntry.groupName,
|
|
1825
|
-
errors: [ `Store ID ${sid} is already assigned to billing group "${doc.groupName}"` ],
|
|
1826
|
-
} );
|
|
1827
|
-
}
|
|
1822
|
+
for ( const doc of otherGroupDocs ) {
|
|
1823
|
+
const movedIds = ( doc.stores || [] )
|
|
1824
|
+
.map( ( sid ) => String( sid ) )
|
|
1825
|
+
.filter( ( sid ) => storeIdToGroup.has( sid ) );
|
|
1826
|
+
if ( movedIds.length > 0 ) {
|
|
1827
|
+
storesToPullByGroupId.set( String( doc._id ), movedIds );
|
|
1828
1828
|
}
|
|
1829
1829
|
}
|
|
1830
1830
|
}
|
|
@@ -1839,6 +1839,19 @@ export async function bulkUpdateBillingGroups( req, res ) {
|
|
|
1839
1839
|
|
|
1840
1840
|
const openSearchActivityLog = JSON.parse( process.env.OPENSEARCH ).activityLog;
|
|
1841
1841
|
|
|
1842
|
+
// Move pass: pull claimed stores out of any OTHER existing DB group first,
|
|
1843
|
+
// so a moved store never ends up assigned to two groups. Groups included in
|
|
1844
|
+
// this upload have their stores[] fully rewritten below, so only the
|
|
1845
|
+
// not-in-upload old groups need an explicit $pull here.
|
|
1846
|
+
for ( const [ oldGroupId, storeIds ] of storesToPullByGroupId ) {
|
|
1847
|
+
try {
|
|
1848
|
+
await billingService.updateOne( { _id: oldGroupId }, { $pull: { stores: { $in: storeIds } } } );
|
|
1849
|
+
} catch ( pullErr ) {
|
|
1850
|
+
logger.error( { error: pullErr, function: 'bulkUpdateBillingGroups.pull', oldGroupId } );
|
|
1851
|
+
return res.sendError( { error: `Failed to release stores from a previous group: ${pullErr?.message || pullErr}` }, 500 );
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1842
1855
|
// Seventh pass: serial DB writes — one per billing group.
|
|
1843
1856
|
let updated = 0;
|
|
1844
1857
|
let aborted = null;
|
|
@@ -143,10 +143,18 @@ export async function createInvoice( req, res ) {
|
|
|
143
143
|
// the auto-generated advance invoices).
|
|
144
144
|
const customAdvanceMonths = req.body.advanceInvoice ?
|
|
145
145
|
( { quarterly: 3, halfyearly: 6, yearly: 12 }[req.body.advancePeriod] || 1 ) : 1;
|
|
146
|
+
// Advance invoices bill the UPCOMING period, so the first month label is
|
|
147
|
+
// NEXT month (start of month), matching the auto-generate branch's
|
|
148
|
+
// baseDate. Without this the labels started on the CURRENT month
|
|
149
|
+
// (e.g. quarterly in Jul produced Jul/Aug/Sep instead of Aug/Sep/Oct).
|
|
150
|
+
// billingDate / monthOfbilling / dueDate below keep using baseDate
|
|
151
|
+
// (creation date), also matching the auto path.
|
|
152
|
+
const advanceStart = req.body.advanceInvoice ?
|
|
153
|
+
dayjs().add( 1, 'month' ).startOf( 'month' ) : baseDate;
|
|
146
154
|
if ( customAdvanceMonths > 1 ) {
|
|
147
155
|
const expanded = [];
|
|
148
156
|
for ( let m = 0; m < customAdvanceMonths; m++ ) {
|
|
149
|
-
const monthLabel =
|
|
157
|
+
const monthLabel = advanceStart.add( m, 'month' ).format( 'MMM YYYY' );
|
|
150
158
|
for ( const p of customProducts ) {
|
|
151
159
|
expanded.push( { ...p, month: monthLabel } );
|
|
152
160
|
}
|