@zeniai/client-epic-state 5.1.35-betaRR1 → 5.1.36
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/lib/esm/index.js +4 -4
- package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +0 -19
- package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +2 -69
- package/lib/esm/view/transactionDetail/journalEntryLinesViewModel.js +0 -58
- package/lib/esm/view/transactionDetail/transactionDetailReducer.js +1 -66
- package/lib/index.d.ts +4 -4
- package/lib/index.js +29 -33
- package/lib/view/transactionDetail/epics/saveTransactionHelper.js +0 -19
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.d.ts +1 -5
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +3 -71
- package/lib/view/transactionDetail/journalEntryLinesViewModel.d.ts +0 -27
- package/lib/view/transactionDetail/journalEntryLinesViewModel.js +1 -61
- package/lib/view/transactionDetail/transactionDetailReducer.d.ts +2 -11
- package/lib/view/transactionDetail/transactionDetailReducer.js +2 -67
- package/lib/view/transactionDetail/transactionDetailState.d.ts +1 -8
- package/lib/view/transactionDetail/transactionDetailTypes.d.ts +0 -2
- package/package.json +7 -6
package/lib/esm/index.js
CHANGED
|
@@ -394,9 +394,9 @@ import { getAllTopExpenses, getTop6Expenses, getTopExpenses, } from './view/topE
|
|
|
394
394
|
*/
|
|
395
395
|
import { TOP_EX_TIME_PERIODS, } from './view/topEx/topExState';
|
|
396
396
|
import { getAccountingProviderAttachment, } from './view/transactionDetail/getAccountingProviderAttachmentSelector';
|
|
397
|
-
import { JOURNAL_ENTRY_SORT_KEYS, filterJournalEntryLinesExcludingLinked, journalEntryDefaultSortConfig,
|
|
397
|
+
import { JOURNAL_ENTRY_SORT_KEYS, filterJournalEntryLinesExcludingLinked, journalEntryDefaultSortConfig, journalEntryTotalsByPostingSide, sortJournalEntryLines, sumJournalEntryAmounts, toJournalEntrySortKey, } from './view/transactionDetail/journalEntryLinesViewModel';
|
|
398
398
|
import { getChangedLineItemCountFromLocalData, isAccountUncategorized, } from './view/transactionDetail/transactionDetailLocalDataHelper';
|
|
399
|
-
import {
|
|
399
|
+
import { clearTransactionDetailSaveStatus, deleteTransactionAttachment, downloadAccountingProviderAttachment, downloadAccountingProviderAttachmentFailure, downloadAccountingProviderAttachmentSuccess, fetchTransactionDetail, initializeTransactionDetailLocalData, markCategoryClassRecommendationsFailureForTransactionDetail, removeEntityRecommendationForLineIdForTransactionDetail, resetAllLineItemsToVendor, resetLineItemsCategoryClassInLocalData, resetSelectedCustomer, resetVendor, saveTransactionDetail, saveTransactionDetailLocalData, setAllLineItemsLocalDataIsUpdateAllChecked, setAllLineItemsToCategoryClassInLocalData, setIsVendorUpdateAllChecked, updateLatestSelectedEntity, updateLocalDataWithTransactionsUpdateWithVendorCheckbox, updateSelectedCustomer, updateSelectedVendor, updateTransactionDetail, updateVendorBulkRecommendationsFetchStatus, updateVendorToAllLineItems, uploadMissingAttachmentSuccess, } from './view/transactionDetail/transactionDetailReducer';
|
|
400
400
|
import { getInitialUpdatablePeriodsForTransactionRecommendations, getTransactionDetail, getTransactionDetailForTransaction, } from './view/transactionDetail/transactionDetailSelector';
|
|
401
401
|
import { getThirdPartyIdFromTransactionId, } from './view/transactionDetail/transactionDetailState';
|
|
402
402
|
import { getTransactionListByAccount, getTransactionListUIStateByAccountKey, } from './view/transactionList/transactionListByAccountSelector';
|
|
@@ -515,7 +515,7 @@ export { isTransferTransaction };
|
|
|
515
515
|
export { getSupportedTransactionById, };
|
|
516
516
|
export { clearTransactionList, updateLatestTransactionId, parallelFetchAccountTransactionList, parallelFetchEntityTransactionList, fetchAccountTransactionList, updateTransactionListByAccount, updateTransactionListByAccountFailure, updateTransactionListByAccountUIState, parallelFetchClassTransactionList, updateTransactionListByClassUIState, updateTransactionListByClass, parallelFetchProjectTransactionList, updateTransactionListByProjectUIState, updateTransactionListByProject, updateTransactionListUIStateByCategoryType, parallelFetchTransactionListByCategoryType, };
|
|
517
517
|
export { getTransactionListByAccount, getTransactionListUIStateByAccountKey, };
|
|
518
|
-
export { fetchEntityTransactionList, updateTransactionListByEntity, saveTransactionDetailLocalData, clearTransactionDetailSaveStatus, updateTransactionListByEntityFailure, resetLineItemsCategoryClassInLocalData, setAllLineItemsToCategoryClassInLocalData, saveTransactionDetail, setAllLineItemsLocalDataIsUpdateAllChecked, initializeTransactionDetailLocalData, markCategoryClassRecommendationsFailureForTransactionDetail, removeEntityRecommendationForLineIdForTransactionDetail, updateSelectedVendor, updateSelectedCustomer, resetSelectedCustomer, resetVendor, updateLocalDataWithTransactionsUpdateWithVendorCheckbox, updateVendorToAllLineItems, resetAllLineItemsToVendor, updateLatestSelectedEntity, updateVendorBulkRecommendationsFetchStatus, setIsVendorUpdateAllChecked,
|
|
518
|
+
export { fetchEntityTransactionList, updateTransactionListByEntity, saveTransactionDetailLocalData, clearTransactionDetailSaveStatus, updateTransactionListByEntityFailure, resetLineItemsCategoryClassInLocalData, setAllLineItemsToCategoryClassInLocalData, saveTransactionDetail, setAllLineItemsLocalDataIsUpdateAllChecked, initializeTransactionDetailLocalData, markCategoryClassRecommendationsFailureForTransactionDetail, removeEntityRecommendationForLineIdForTransactionDetail, updateSelectedVendor, updateSelectedCustomer, resetSelectedCustomer, resetVendor, updateLocalDataWithTransactionsUpdateWithVendorCheckbox, updateVendorToAllLineItems, resetAllLineItemsToVendor, updateLatestSelectedEntity, updateVendorBulkRecommendationsFetchStatus, setIsVendorUpdateAllChecked, };
|
|
519
519
|
export { downloadAccountingProviderAttachment, downloadAccountingProviderAttachmentSuccess, downloadAccountingProviderAttachmentFailure, fetchTransactionDetail, updateTransactionDetail, uploadMissingAttachmentSuccess, deleteTransactionAttachment, getThirdPartyIdFromTransactionId, };
|
|
520
520
|
export { getTransactionListByEntity };
|
|
521
521
|
export { getTransactionListByClass, getTransactionListUIStateByClassKey, getTransactionListByProject, getTransactionListUIStateByProjectKey, getTransactionListByEntityForSinglePeriod, };
|
|
@@ -594,7 +594,7 @@ export { getNextNthWorkingDay, getNextTransferDate, getPreviousNthWorkingDay, is
|
|
|
594
594
|
export { fetchCompanyOnboardingView, fetchQBOConnectionPool, updateQBOConnectionPoolExternalConnection, fetchOnboardingCompletedCompanies, saveOnboardingCustomerCompletedStatus, toProductType, toProductTypeStrict, getOnboardingCockpitView, getNewOnboardingCustomerView, getOnboardingEmailGroup, initializeOnboardingCustomerViewUpdateData, clearOnboardingCustomerViewUpdateData, saveOnboardingCustomerViewUpdateData, updateOnboardingCustomerListUIState, updateCustomerCreationStatus, updateStatusAfterOnboardingCompleted, saveOnboardingCustomerViewUpdates, saveOnboardingCustomerNotes, saveOnboardingCustomerDataInLocalStore, updateOnboardingCustomerDataInLocalStore, resetNewOnboardedCustomerId, sendOnboardingCustomerViewInvite, retryBankAccountConnectionForOnboarding, };
|
|
595
595
|
export { getTransactionsListByCategoryType, getTransactionListUIStateByCategoryType, };
|
|
596
596
|
export { getChangedLineItemCountFromLocalData, isAccountUncategorized };
|
|
597
|
-
export { JOURNAL_ENTRY_SORT_KEYS, filterJournalEntryLinesExcludingLinked, journalEntryDefaultSortConfig, journalEntryTotalsByPostingSide,
|
|
597
|
+
export { JOURNAL_ENTRY_SORT_KEYS, filterJournalEntryLinesExcludingLinked, journalEntryDefaultSortConfig, journalEntryTotalsByPostingSide, sortJournalEntryLines, sumJournalEntryAmounts, toJournalEntrySortKey, };
|
|
598
598
|
export { openSnackbar, closeSnackbar, getSnackbar, };
|
|
599
599
|
export { getSpendManagementEffectiveListPeriod, getSelectedCompanyOfficer, showBillPayPromoPage, showReimbursementPromoPage, getActualPaymentDate, isVerifiedStatusCode, isVerifiedPaymentAccountProviderStatusCode, isBulkProcessing, getBillListUniqueType, getRemiListUniqueType, getBulkOperationSuffix, toAccountsPromoConfig, toSameDayAchDisablementConfig, isPaymentMethodOutsideZeni, isAwaitingMarkAsPaid, checkIfLowBalance, };
|
|
600
600
|
export { canSendMonthEndEmailReport, shouldEnableCalendarPickerForLastReportSent, };
|
|
@@ -45,15 +45,7 @@ export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDe
|
|
|
45
45
|
let lastUpdatedCategory;
|
|
46
46
|
let lastUpdatedClass;
|
|
47
47
|
// single recommendation to just pick the last recommendation in the list of lines
|
|
48
|
-
const deletedLineIds = new Set(transactionDetailLocalData.deletedLineIds ?? []);
|
|
49
|
-
const existingLineIds = new Set(transaction.lines?.map((l) => l.id) ?? []);
|
|
50
|
-
// Collect new lines — in lineItemById but not yet in transaction.lines.
|
|
51
|
-
const addedLines = Object.values(transactionDetailLocalData.lineItemById).filter((item) => !existingLineIds.has(item.id));
|
|
52
48
|
transaction.lines?.forEach((line) => {
|
|
53
|
-
// Skip lines the user deleted in edit mode.
|
|
54
|
-
if (deletedLineIds.has(line.id)) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
49
|
const lineItem = transactionDetailLocalData.lineItemById[line.id];
|
|
58
50
|
if (line.type === 'transaction_with_account_and_class_line' ||
|
|
59
51
|
line.type === 'transaction_with_product_or_service_line' ||
|
|
@@ -64,7 +56,6 @@ export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDe
|
|
|
64
56
|
const entityDetails = getEntityDetails(selectedEntity, lineItem, transactionDetailLocalData.vendorUpdates, transactionDetailLocalData.customerUpdates);
|
|
65
57
|
updatesByLineId[line.id] = {
|
|
66
58
|
lineDescription: lineItem.lineDescription,
|
|
67
|
-
amount: lineItem.amount,
|
|
68
59
|
class: lineItem.class,
|
|
69
60
|
account: lineItem.account,
|
|
70
61
|
// Project is at the transaction level for invoice/credit_memo; omit from lines.
|
|
@@ -86,14 +77,6 @@ export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDe
|
|
|
86
77
|
currentSelectedEntityLine.type === 'vendor'
|
|
87
78
|
? lineItem.vendor
|
|
88
79
|
: undefined,
|
|
89
|
-
// Carry the JE debit/credit side so a split edit that flips an
|
|
90
|
-
// existing line's posting side persists through the line patch.
|
|
91
|
-
...(line.type === 'journal_entry_transaction_line'
|
|
92
|
-
? {
|
|
93
|
-
postingType: lineItem.postingType,
|
|
94
|
-
postingTypeName: lineItem.postingTypeName,
|
|
95
|
-
}
|
|
96
|
-
: {}),
|
|
97
80
|
};
|
|
98
81
|
}
|
|
99
82
|
let hasCategoryChanged = false;
|
|
@@ -180,8 +163,6 @@ export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDe
|
|
|
180
163
|
and all the line items are NOT uncategorized*/
|
|
181
164
|
markAsMiscatUpdates: isTransactionMisCategorized,
|
|
182
165
|
anyBulkUpdates: isBulkUpdate,
|
|
183
|
-
addedLines: addedLines.length > 0 ? addedLines : undefined,
|
|
184
|
-
deletedLineIds: deletedLineIds.size > 0 ? [...deletedLineIds] : undefined,
|
|
185
166
|
};
|
|
186
167
|
};
|
|
187
168
|
const doUpdateEntityUpdates = (entityUpdates, entityId, entityType, recommendation, isBulkUpdate = false, updatedEntityId, entityName) => {
|
|
@@ -159,7 +159,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
159
159
|
};
|
|
160
160
|
}
|
|
161
161
|
if (detail != null) {
|
|
162
|
-
const transUpdates = toTransactionUpdatePayload(saveUpdates.updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, currentSelectedEntity
|
|
162
|
+
const transUpdates = toTransactionUpdatePayload(saveUpdates.updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, currentSelectedEntity);
|
|
163
163
|
const entityUpdates = toEntityUpdatePayload(saveUpdates.entityRelatedUpdates);
|
|
164
164
|
return {
|
|
165
165
|
entity_related_updates: entityUpdates,
|
|
@@ -169,7 +169,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
169
169
|
}
|
|
170
170
|
return undefined;
|
|
171
171
|
}
|
|
172
|
-
export const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, tranSelectedEntity
|
|
172
|
+
export const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, tranSelectedEntity) => {
|
|
173
173
|
const transaction = Object.assign({}, detail);
|
|
174
174
|
transaction.memo = updates.memo ?? '';
|
|
175
175
|
// Unlike `memo` (always reset to '' when absent), `documentId` falls back to
|
|
@@ -178,11 +178,6 @@ export const toTransactionUpdatePayload = (updates, detail, cotTransactionTracki
|
|
|
178
178
|
// either the unchanged current value or undefined, and we must not send an
|
|
179
179
|
// empty `document_id` that the server would treat as clearing the number.
|
|
180
180
|
transaction.documentId = updates.documentId ?? transaction.documentId;
|
|
181
|
-
// Remove lines deleted by the user in edit mode before patching or serializing.
|
|
182
|
-
if (deletedLineIds != null && deletedLineIds.length > 0) {
|
|
183
|
-
const deletedSet = new Set(deletedLineIds);
|
|
184
|
-
transaction.lines = transaction.lines?.filter((line) => !deletedSet.has(line.id));
|
|
185
|
-
}
|
|
186
181
|
const recommendationUpdates = {};
|
|
187
182
|
for (const key in updates.updatesByLineId) {
|
|
188
183
|
const lineUpdates = updates.updatesByLineId[key];
|
|
@@ -190,9 +185,6 @@ export const toTransactionUpdatePayload = (updates, detail, cotTransactionTracki
|
|
|
190
185
|
if (line.id === key) {
|
|
191
186
|
const lineTobeUpdated = Object.assign({}, line);
|
|
192
187
|
lineTobeUpdated.lineDescription = lineUpdates.lineDescription ?? '';
|
|
193
|
-
if (lineUpdates.amount != null) {
|
|
194
|
-
lineTobeUpdated.amount = lineUpdates.amount;
|
|
195
|
-
}
|
|
196
188
|
if (lineUpdates.class != null) {
|
|
197
189
|
lineTobeUpdated.class = lineUpdates.class;
|
|
198
190
|
}
|
|
@@ -214,16 +206,6 @@ export const toTransactionUpdatePayload = (updates, detail, cotTransactionTracki
|
|
|
214
206
|
else {
|
|
215
207
|
lineTobeUpdated.vendor = undefined;
|
|
216
208
|
}
|
|
217
|
-
// Persist a debit↔credit flip on an existing JE line. `lineTobeUpdated`
|
|
218
|
-
// is typed as the account-and-class shape, but for a JE the runtime
|
|
219
|
-
// object is a JournalEntryTransactionLine, so cast to set the side.
|
|
220
|
-
if (lineUpdates.postingType != null) {
|
|
221
|
-
const journalEntryLine = lineTobeUpdated;
|
|
222
|
-
journalEntryLine.postingType = lineUpdates.postingType;
|
|
223
|
-
if (lineUpdates.postingTypeName != null) {
|
|
224
|
-
journalEntryLine.postingTypeName = lineUpdates.postingTypeName;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
209
|
if (lineUpdates.recommendation != null) {
|
|
228
210
|
recommendationUpdates[line.id] = lineUpdates.recommendation;
|
|
229
211
|
}
|
|
@@ -243,12 +225,6 @@ export const toTransactionUpdatePayload = (updates, detail, cotTransactionTracki
|
|
|
243
225
|
});
|
|
244
226
|
transaction.lines = newLineMap;
|
|
245
227
|
}
|
|
246
|
-
// Append lines added by the user in edit mode. Sending id='' tells the
|
|
247
|
-
// backend to create a new QBO line rather than updating an existing one.
|
|
248
|
-
if (addedLines != null && addedLines.length > 0) {
|
|
249
|
-
const newLines = addedLines.map(toNewTransactionLine);
|
|
250
|
-
transaction.lines = [...(transaction.lines ?? []), ...newLines];
|
|
251
|
-
}
|
|
252
228
|
transaction.recommendations = recommendationUpdates;
|
|
253
229
|
// Convert transaction to payload first
|
|
254
230
|
let basePayload;
|
|
@@ -323,49 +299,6 @@ const checkIfVendorOrCustomerMissingForAnyLineItem = (transactionPayload) => {
|
|
|
323
299
|
}
|
|
324
300
|
return isAnyVendorOrCustomerMissing;
|
|
325
301
|
};
|
|
326
|
-
// Converts a locally-created line item (from edit mode) into the wire shape
|
|
327
|
-
// expected by the categorize endpoint. Sending id='' signals the backend to
|
|
328
|
-
// create a new QBO line rather than update an existing one.
|
|
329
|
-
//
|
|
330
|
-
// Type-dispatched so each transaction family contributes its own new-line
|
|
331
|
-
// shape: journal entries carry debit/credit `postingType`, expenses carry
|
|
332
|
-
// `billable`. Phase 3 types extend this by adding a branch rather than forking
|
|
333
|
-
// the function.
|
|
334
|
-
const EMPTY_ACCOUNT = {
|
|
335
|
-
accountDescription: '',
|
|
336
|
-
accountId: '',
|
|
337
|
-
accountName: '',
|
|
338
|
-
labels: [],
|
|
339
|
-
};
|
|
340
|
-
export const toNewTransactionLine = (item) => {
|
|
341
|
-
if (item.type === 'journal_entry_transaction_line') {
|
|
342
|
-
const journalEntryLine = {
|
|
343
|
-
...item,
|
|
344
|
-
id: '',
|
|
345
|
-
type: 'journal_entry_transaction_line',
|
|
346
|
-
platformLineDetailType: item.platformLineDetailType ?? 'journal_entry_line_detail',
|
|
347
|
-
account: item.account ?? EMPTY_ACCOUNT,
|
|
348
|
-
billable: item.billable ?? 'not_billable',
|
|
349
|
-
isCategoryMiscategorized: false,
|
|
350
|
-
isClassMiscategorized: false,
|
|
351
|
-
lineTransactionType: item.lineTransactionType ?? 'journal_entry',
|
|
352
|
-
postingType: item.postingType ?? 'debit',
|
|
353
|
-
postingTypeName: item.postingTypeName ?? '',
|
|
354
|
-
};
|
|
355
|
-
return journalEntryLine;
|
|
356
|
-
}
|
|
357
|
-
const accountAndClassLine = {
|
|
358
|
-
...item,
|
|
359
|
-
id: '',
|
|
360
|
-
type: 'transaction_with_account_and_class_line',
|
|
361
|
-
platformLineDetailType: item.platformLineDetailType ?? 'account_based_expense_line_detail',
|
|
362
|
-
account: item.account ?? EMPTY_ACCOUNT,
|
|
363
|
-
billable: item.billable ?? 'not_billable',
|
|
364
|
-
isCategoryMiscategorized: false,
|
|
365
|
-
isClassMiscategorized: false,
|
|
366
|
-
};
|
|
367
|
-
return accountAndClassLine;
|
|
368
|
-
};
|
|
369
302
|
const toEntityUpdatePayload = (entityUpdates) => {
|
|
370
303
|
const entityUpdatesPayload = [];
|
|
371
304
|
let entityKey;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import Big from 'big.js';
|
|
2
1
|
import orderBy from 'lodash/orderBy';
|
|
3
2
|
import { stringToUnion } from '../../commonStateTypes/stringToUnion';
|
|
4
3
|
import { LINE_TYPE_LINKED, } from '../../entity/transaction/stateTypes/transactionLine';
|
|
@@ -102,63 +101,6 @@ export const journalEntryTotalsByPostingSide = (lines) => {
|
|
|
102
101
|
};
|
|
103
102
|
};
|
|
104
103
|
// ---------------------------------------------------------------------------
|
|
105
|
-
// Split reconciliation & validation (Phase 2 — JE split)
|
|
106
|
-
// ---------------------------------------------------------------------------
|
|
107
|
-
// Half-cent tolerance for the balance equality checks, matching the expense
|
|
108
|
-
// reconciliation row's epsilon. Sums use big.js so repeated decimal addition
|
|
109
|
-
// doesn't drift before the comparison.
|
|
110
|
-
const JOURNAL_ENTRY_BALANCE_EPSILON = 0.005;
|
|
111
|
-
/**
|
|
112
|
-
* Sums debit and credit sides (big.js-exact) and reports whether the split is
|
|
113
|
-
* balanced: total debits equal total credits AND equal the original
|
|
114
|
-
* transaction total. The original total of a valid JE equals its total debits,
|
|
115
|
-
* so it is passed in by the caller (`transaction.amount.amount`).
|
|
116
|
-
*/
|
|
117
|
-
export const journalEntrySplitReconciliation = (lines, originalTotal) => {
|
|
118
|
-
let debit = new Big(0);
|
|
119
|
-
let credit = new Big(0);
|
|
120
|
-
for (const line of lines) {
|
|
121
|
-
const amount = new Big(line.amount?.amount ?? 0);
|
|
122
|
-
if (line.postingType === 'debit') {
|
|
123
|
-
debit = debit.plus(amount);
|
|
124
|
-
}
|
|
125
|
-
else if (line.postingType === 'credit') {
|
|
126
|
-
credit = credit.plus(amount);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
const balancedToEachOther = debit
|
|
130
|
-
.minus(credit)
|
|
131
|
-
.abs()
|
|
132
|
-
.lt(JOURNAL_ENTRY_BALANCE_EPSILON);
|
|
133
|
-
const balancedToOriginal = debit
|
|
134
|
-
.minus(originalTotal)
|
|
135
|
-
.abs()
|
|
136
|
-
.lt(JOURNAL_ENTRY_BALANCE_EPSILON);
|
|
137
|
-
return {
|
|
138
|
-
debitTotal: debit.toNumber(),
|
|
139
|
-
creditTotal: credit.toNumber(),
|
|
140
|
-
isBalanced: balancedToEachOther && balancedToOriginal,
|
|
141
|
-
};
|
|
142
|
-
};
|
|
143
|
-
/**
|
|
144
|
-
* Save-time validation for a JE split (Figma `4165:33028` / `4165:45379`):
|
|
145
|
-
* 1. every line needs a non-zero debit or credit, and
|
|
146
|
-
* 2. total debits == total credits == original total.
|
|
147
|
-
* Returns the first failing rule's `errorKey` (maps to a strings entry). Does
|
|
148
|
-
* NOT require category/class to be chosen — balance is the only gate.
|
|
149
|
-
*/
|
|
150
|
-
export const validateJournalEntrySplit = (lines, originalTotal) => {
|
|
151
|
-
const everyLineHasSide = lines.every((line) => (line.postingType === 'debit' || line.postingType === 'credit') &&
|
|
152
|
-
Math.abs(line.amount?.amount ?? 0) > JOURNAL_ENTRY_BALANCE_EPSILON);
|
|
153
|
-
if (!everyLineHasSide) {
|
|
154
|
-
return { ok: false, errorKey: 'lineNeedsDebitOrCredit' };
|
|
155
|
-
}
|
|
156
|
-
if (!journalEntrySplitReconciliation(lines, originalTotal).isBalanced) {
|
|
157
|
-
return { ok: false, errorKey: 'totalsMustEqual' };
|
|
158
|
-
}
|
|
159
|
-
return { ok: true };
|
|
160
|
-
};
|
|
161
|
-
// ---------------------------------------------------------------------------
|
|
162
104
|
// Filter
|
|
163
105
|
// ---------------------------------------------------------------------------
|
|
164
106
|
/**
|
|
@@ -663,71 +663,6 @@ const transactionDetail = createSlice({
|
|
|
663
663
|
};
|
|
664
664
|
},
|
|
665
665
|
},
|
|
666
|
-
// Split transaction — Phase 1 (expense)
|
|
667
|
-
addSplitLine: {
|
|
668
|
-
reducer(draft, action) {
|
|
669
|
-
const key = getTransactionDetailKey(action.payload.transactionId);
|
|
670
|
-
const detail = recordGet(draft.transactionDetailById, key, undefined);
|
|
671
|
-
if (detail != null) {
|
|
672
|
-
draft.transactionDetailById[key] = {
|
|
673
|
-
...detail,
|
|
674
|
-
transactionDetailLocalData: {
|
|
675
|
-
...detail.transactionDetailLocalData,
|
|
676
|
-
lineItemById: {
|
|
677
|
-
...detail.transactionDetailLocalData.lineItemById,
|
|
678
|
-
[action.payload.newLine.id]: action.payload.newLine,
|
|
679
|
-
},
|
|
680
|
-
},
|
|
681
|
-
};
|
|
682
|
-
}
|
|
683
|
-
},
|
|
684
|
-
prepare(transactionId, newLine) {
|
|
685
|
-
return { payload: { transactionId, newLine } };
|
|
686
|
-
},
|
|
687
|
-
},
|
|
688
|
-
deleteSplitLine: {
|
|
689
|
-
reducer(draft, action) {
|
|
690
|
-
const key = getTransactionDetailKey(action.payload.transactionId);
|
|
691
|
-
const detail = recordGet(draft.transactionDetailById, key, undefined);
|
|
692
|
-
if (detail == null) {
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
const { lineItemById, deletedLineIds = [] } = detail.transactionDetailLocalData;
|
|
696
|
-
const updated = { ...lineItemById };
|
|
697
|
-
delete updated[action.payload.lineId];
|
|
698
|
-
draft.transactionDetailById[key] = {
|
|
699
|
-
...detail,
|
|
700
|
-
transactionDetailLocalData: {
|
|
701
|
-
...detail.transactionDetailLocalData,
|
|
702
|
-
lineItemById: updated,
|
|
703
|
-
deletedLineIds: [...deletedLineIds, action.payload.lineId],
|
|
704
|
-
},
|
|
705
|
-
};
|
|
706
|
-
},
|
|
707
|
-
prepare(transactionId, lineId) {
|
|
708
|
-
return { payload: { transactionId, lineId } };
|
|
709
|
-
},
|
|
710
|
-
},
|
|
711
|
-
toggleSplitEditMode: {
|
|
712
|
-
reducer(draft, action) {
|
|
713
|
-
const key = getTransactionDetailKey(action.payload.transactionId);
|
|
714
|
-
const detail = recordGet(draft.transactionDetailById, key, undefined);
|
|
715
|
-
if (detail != null) {
|
|
716
|
-
draft.transactionDetailById[key] = {
|
|
717
|
-
...detail,
|
|
718
|
-
transactionDetailLocalData: {
|
|
719
|
-
...detail.transactionDetailLocalData,
|
|
720
|
-
editMode: action.payload.editMode,
|
|
721
|
-
// Clear delete tracking when exiting edit mode without saving.
|
|
722
|
-
...(!action.payload.editMode && { deletedLineIds: [] }),
|
|
723
|
-
},
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
},
|
|
727
|
-
prepare(transactionId, editMode) {
|
|
728
|
-
return { payload: { transactionId, editMode } };
|
|
729
|
-
},
|
|
730
|
-
},
|
|
731
666
|
clearRecommendedVendorsList(draft) {
|
|
732
667
|
Object.assign(draft, initialState);
|
|
733
668
|
},
|
|
@@ -836,7 +771,7 @@ const transactionDetail = createSlice({
|
|
|
836
771
|
},
|
|
837
772
|
},
|
|
838
773
|
});
|
|
839
|
-
export const { downloadAccountingProviderAttachment, downloadAccountingProviderAttachmentSuccess, downloadAccountingProviderAttachmentFailure, fetchTransactionDetail, updateTransactionDetailFetchState, removeTransactionDetail, clearTransactionDetail, uploadMissingAttachmentSuccess, updateTransactionDetail, updateTransactionDetailSaveStatus, clearTransactionDetailSaveStatus, markTransactionAsNotMiscategorized, deleteTransactionAttachment, deleteTransactionAttachmentFailure, deleteTransactionAttachmentSuccess, updateStatusForTransactionNotMiscategorizedUpdate, updateStatusConsolidatedSaveTransactionDetail, updateTransactionStateIfUpdateActionNotAllowed, saveTransactionDetail, initializeTransactionDetailLocalData, saveTransactionDetailLocalData, clearTransactionDetailLocalData, resetLineItemsCategoryClassInLocalData, setAllLineItemsToCategoryClassInLocalData, setAllLineItemsLocalDataIsUpdateAllChecked, setEntityRecommendationForLineIdsForTransactionDetail, markCategoryClassRecommendationsInProgressForTransactionDetail, markCategoryClassRecommendationsCompletedForTransactionDetail, markCategoryClassRecommendationsFailureForTransactionDetail, removeEntityRecommendationForLineIdForTransactionDetail, updateSelectedVendor, updateSelectedCustomer, resetVendor, resetSelectedCustomer, updateLocalDataWithTransactionsUpdateWithVendorCheckbox, updateVendorToAllLineItems, resetAllLineItemsToVendor, updateLatestSelectedEntity, updateVendorBulkRecommendationsFetchStatus, setIsVendorUpdateAllChecked,
|
|
774
|
+
export const { downloadAccountingProviderAttachment, downloadAccountingProviderAttachmentSuccess, downloadAccountingProviderAttachmentFailure, fetchTransactionDetail, updateTransactionDetailFetchState, removeTransactionDetail, clearTransactionDetail, uploadMissingAttachmentSuccess, updateTransactionDetail, updateTransactionDetailSaveStatus, clearTransactionDetailSaveStatus, markTransactionAsNotMiscategorized, deleteTransactionAttachment, deleteTransactionAttachmentFailure, deleteTransactionAttachmentSuccess, updateStatusForTransactionNotMiscategorizedUpdate, updateStatusConsolidatedSaveTransactionDetail, updateTransactionStateIfUpdateActionNotAllowed, saveTransactionDetail, initializeTransactionDetailLocalData, saveTransactionDetailLocalData, clearTransactionDetailLocalData, resetLineItemsCategoryClassInLocalData, setAllLineItemsToCategoryClassInLocalData, setAllLineItemsLocalDataIsUpdateAllChecked, setEntityRecommendationForLineIdsForTransactionDetail, markCategoryClassRecommendationsInProgressForTransactionDetail, markCategoryClassRecommendationsCompletedForTransactionDetail, markCategoryClassRecommendationsFailureForTransactionDetail, removeEntityRecommendationForLineIdForTransactionDetail, updateSelectedVendor, updateSelectedCustomer, resetVendor, resetSelectedCustomer, updateLocalDataWithTransactionsUpdateWithVendorCheckbox, updateVendorToAllLineItems, resetAllLineItemsToVendor, updateLatestSelectedEntity, updateVendorBulkRecommendationsFetchStatus, setIsVendorUpdateAllChecked, } = transactionDetail.actions;
|
|
840
775
|
export default transactionDetail.reducer;
|
|
841
776
|
function getUpdatedEntityLocalData(detail, updates, entity, resetRecommendations, type) {
|
|
842
777
|
const key = type === 'customer' ? 'customerUpdates' : 'vendorUpdates';
|
package/lib/index.d.ts
CHANGED
|
@@ -581,9 +581,9 @@ import { TopExAccount, TopExReport, TopExTimePeriodWithMetaData, TopExpenses } f
|
|
|
581
581
|
*/
|
|
582
582
|
import { TOP_EX_TIME_PERIODS, TopExTimePeriod, TopExpense } from './view/topEx/topExState';
|
|
583
583
|
import { AccountingProviderAttachmentSelector, getAccountingProviderAttachment } from './view/transactionDetail/getAccountingProviderAttachmentSelector';
|
|
584
|
-
import { JOURNAL_ENTRY_SORT_KEYS, JournalEntryRowSortConfig, JournalEntrySortAccessors, JournalEntrySortKey, filterJournalEntryLinesExcludingLinked, journalEntryDefaultSortConfig,
|
|
584
|
+
import { JOURNAL_ENTRY_SORT_KEYS, JournalEntryRowSortConfig, JournalEntrySortAccessors, JournalEntrySortKey, filterJournalEntryLinesExcludingLinked, journalEntryDefaultSortConfig, journalEntryTotalsByPostingSide, sortJournalEntryLines, sumJournalEntryAmounts, toJournalEntrySortKey } from './view/transactionDetail/journalEntryLinesViewModel';
|
|
585
585
|
import { getChangedLineItemCountFromLocalData, isAccountUncategorized } from './view/transactionDetail/transactionDetailLocalDataHelper';
|
|
586
|
-
import {
|
|
586
|
+
import { clearTransactionDetailSaveStatus, deleteTransactionAttachment, downloadAccountingProviderAttachment, downloadAccountingProviderAttachmentFailure, downloadAccountingProviderAttachmentSuccess, fetchTransactionDetail, initializeTransactionDetailLocalData, markCategoryClassRecommendationsFailureForTransactionDetail, removeEntityRecommendationForLineIdForTransactionDetail, resetAllLineItemsToVendor, resetLineItemsCategoryClassInLocalData, resetSelectedCustomer, resetVendor, saveTransactionDetail, saveTransactionDetailLocalData, setAllLineItemsLocalDataIsUpdateAllChecked, setAllLineItemsToCategoryClassInLocalData, setIsVendorUpdateAllChecked, updateLatestSelectedEntity, updateLocalDataWithTransactionsUpdateWithVendorCheckbox, updateSelectedCustomer, updateSelectedVendor, updateTransactionDetail, updateVendorBulkRecommendationsFetchStatus, updateVendorToAllLineItems, uploadMissingAttachmentSuccess } from './view/transactionDetail/transactionDetailReducer';
|
|
587
587
|
import { TransactionDetailReport, VendorDetailsView, getInitialUpdatablePeriodsForTransactionRecommendations, getTransactionDetail, getTransactionDetailForTransaction } from './view/transactionDetail/transactionDetailSelector';
|
|
588
588
|
import { TransactionUpdates, getThirdPartyIdFromTransactionId } from './view/transactionDetail/transactionDetailState';
|
|
589
589
|
import { TransactionDetailLineItemData, TransactionDetailLocalData, TransactionVendorUpdates } from './view/transactionDetail/transactionDetailTypes';
|
|
@@ -742,7 +742,7 @@ export { MatchedTransaction };
|
|
|
742
742
|
export { SupportedTransaction, SupportedTransactionWithCOT, SupportedTransactionPayload, getSupportedTransactionById, };
|
|
743
743
|
export { clearTransactionList, updateLatestTransactionId, parallelFetchAccountTransactionList, parallelFetchEntityTransactionList, fetchAccountTransactionList, updateTransactionListByAccount, updateTransactionListByAccountFailure, updateTransactionListByAccountUIState, parallelFetchClassTransactionList, updateTransactionListByClassUIState, updateTransactionListByClass, parallelFetchProjectTransactionList, updateTransactionListByProjectUIState, updateTransactionListByProject, updateTransactionListUIStateByCategoryType, parallelFetchTransactionListByCategoryType, };
|
|
744
744
|
export { TransactionListByAccountReport, getTransactionListByAccount, getTransactionListUIStateByAccountKey, };
|
|
745
|
-
export { fetchEntityTransactionList, updateTransactionListByEntity, saveTransactionDetailLocalData, clearTransactionDetailSaveStatus, updateTransactionListByEntityFailure, resetLineItemsCategoryClassInLocalData, setAllLineItemsToCategoryClassInLocalData, saveTransactionDetail, setAllLineItemsLocalDataIsUpdateAllChecked, initializeTransactionDetailLocalData, markCategoryClassRecommendationsFailureForTransactionDetail, removeEntityRecommendationForLineIdForTransactionDetail, updateSelectedVendor, updateSelectedCustomer, resetSelectedCustomer, resetVendor, updateLocalDataWithTransactionsUpdateWithVendorCheckbox, updateVendorToAllLineItems, resetAllLineItemsToVendor, updateLatestSelectedEntity, updateVendorBulkRecommendationsFetchStatus, setIsVendorUpdateAllChecked,
|
|
745
|
+
export { fetchEntityTransactionList, updateTransactionListByEntity, saveTransactionDetailLocalData, clearTransactionDetailSaveStatus, updateTransactionListByEntityFailure, resetLineItemsCategoryClassInLocalData, setAllLineItemsToCategoryClassInLocalData, saveTransactionDetail, setAllLineItemsLocalDataIsUpdateAllChecked, initializeTransactionDetailLocalData, markCategoryClassRecommendationsFailureForTransactionDetail, removeEntityRecommendationForLineIdForTransactionDetail, updateSelectedVendor, updateSelectedCustomer, resetSelectedCustomer, resetVendor, updateLocalDataWithTransactionsUpdateWithVendorCheckbox, updateVendorToAllLineItems, resetAllLineItemsToVendor, updateLatestSelectedEntity, updateVendorBulkRecommendationsFetchStatus, setIsVendorUpdateAllChecked, };
|
|
746
746
|
export { TransactionUpdates, downloadAccountingProviderAttachment, downloadAccountingProviderAttachmentSuccess, downloadAccountingProviderAttachmentFailure, fetchTransactionDetail, updateTransactionDetail, uploadMissingAttachmentSuccess, deleteTransactionAttachment, getThirdPartyIdFromTransactionId, };
|
|
747
747
|
export { TransactionListByEntityView, getTransactionListByEntity };
|
|
748
748
|
export { TransactionListByClassReport, getTransactionListByClass, getTransactionListUIStateByClassKey, TransactionListByProjectReport, getTransactionListByProject, getTransactionListUIStateByProjectKey, getTransactionListByEntityForSinglePeriod, };
|
|
@@ -842,7 +842,7 @@ export { fetchCompanyOnboardingView, fetchQBOConnectionPool, updateQBOConnection
|
|
|
842
842
|
export { TransactionListByCategoryType, getTransactionsListByCategoryType, getTransactionListUIStateByCategoryType, TransactionCategoryType, };
|
|
843
843
|
export { TransactionDetailLocalData, TransactionDetailLineItemData, TransactionVendorUpdates, };
|
|
844
844
|
export { getChangedLineItemCountFromLocalData, isAccountUncategorized };
|
|
845
|
-
export { JOURNAL_ENTRY_SORT_KEYS, filterJournalEntryLinesExcludingLinked, journalEntryDefaultSortConfig, journalEntryTotalsByPostingSide,
|
|
845
|
+
export { JOURNAL_ENTRY_SORT_KEYS, filterJournalEntryLinesExcludingLinked, journalEntryDefaultSortConfig, journalEntryTotalsByPostingSide, sortJournalEntryLines, sumJournalEntryAmounts, toJournalEntrySortKey, };
|
|
846
846
|
export type { JournalEntryRowSortConfig, JournalEntrySortAccessors, JournalEntrySortKey, };
|
|
847
847
|
export { openSnackbar, closeSnackbar, getSnackbar, SnackbarMessageType, SnackbarMessageSections, SnackbarMessageSectionTexts, SnackbarMessageConfig, };
|
|
848
848
|
export { getSpendManagementEffectiveListPeriod, getSelectedCompanyOfficer, showBillPayPromoPage, showReimbursementPromoPage, getActualPaymentDate, isVerifiedStatusCode, isVerifiedPaymentAccountProviderStatusCode, isBulkProcessing, getBillListUniqueType, getRemiListUniqueType, BulkOperationType, BulkOperationFinishedType, getBulkOperationSuffix, ZeniAccountsPromoConfig, toAccountsPromoConfig, SameDayAchDisablementConfig, toSameDayAchDisablementConfig, isPaymentMethodOutsideZeni, isAwaitingMarkAsPaid, checkIfLowBalance, };
|