@zeniai/client-epic-state 5.1.18-betaDI11 → 5.1.18-betaDI12
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/README.md +3 -1
- package/lib/commonStateTypes/viewAndReport/agingReportStateTypes.d.ts +1 -1
- package/lib/entity/accountRecon/accountReconPayload.d.ts +22 -0
- package/lib/entity/accountRecon/accountReconPayload.js +26 -1
- package/lib/entity/accountRecon/accountReconReducer.d.ts +5 -2
- package/lib/entity/accountRecon/accountReconReducer.js +36 -2
- package/lib/entity/accountRecon/accountReconSelector.d.ts +6 -1
- package/lib/entity/accountRecon/accountReconSelector.js +5 -0
- package/lib/entity/accountRecon/accountReconState.d.ts +22 -0
- package/lib/entity/monthEndCloseChecks/monthEndCloseChecksPayload.d.ts +8 -0
- package/lib/entity/monthEndCloseChecks/monthEndCloseChecksPayload.js +10 -0
- package/lib/entity/monthEndCloseChecks/monthEndCloseChecksState.d.ts +8 -0
- package/lib/entity/task/taskReducer.js +3 -0
- package/lib/entity/task/taskState.d.ts +1 -1
- package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +1 -0
- package/lib/entity/transaction/payloadTypes/transactionPayload.js +5 -0
- package/lib/entity/transaction/stateTypes/transaction.d.ts +1 -0
- package/lib/epic.d.ts +7 -2
- package/lib/epic.js +7 -2
- package/lib/esm/entity/accountRecon/accountReconPayload.js +26 -1
- package/lib/esm/entity/accountRecon/accountReconReducer.js +35 -1
- package/lib/esm/entity/accountRecon/accountReconSelector.js +5 -0
- package/lib/esm/entity/monthEndCloseChecks/monthEndCloseChecksPayload.js +10 -0
- package/lib/esm/entity/task/taskReducer.js +3 -0
- package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +5 -0
- package/lib/esm/epic.js +7 -2
- package/lib/esm/index.js +9 -9
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +29 -3
- package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +11 -0
- package/lib/esm/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -2
- package/lib/esm/view/aiCfoView/epics/fetchSkillsEpic.js +34 -0
- package/lib/esm/view/aiCfoView/epics/submitQuestionEpic.js +7 -1
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.js +34 -0
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/reparseStatementEpic.js +31 -0
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.js +57 -0
- package/lib/esm/view/expenseAutomationView/epics/fluxAnalysis/fetchFluxAnalysisViewEpic.js +1 -0
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +49 -11
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +30 -3
- package/lib/esm/view/expenseAutomationView/payload/reconciliationPayload.js +153 -0
- package/lib/esm/view/expenseAutomationView/reducers/fluxAnalysisViewReducer.js +6 -1
- package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +188 -9
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +37 -17
- package/lib/esm/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +2 -1
- package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +27 -0
- package/lib/esm/view/expenseAutomationView/types/reconciliationViewState.js +29 -0
- package/lib/esm/view/onboardingView/cockpitView/epic/initializeOnboardingCustomerViewUpdateDataEpic.js +4 -16
- package/lib/esm/view/onboardingView/cockpitView/onboardingCockpitViewPayload.js +2 -2
- package/lib/esm/view/opExByVendor/opExByVendorReducer.js +28 -5
- package/lib/esm/view/opExByVendor/opExByVendorSelector.js +1 -0
- package/lib/esm/view/opExByVendor/refreshOpExByVendorReportEpic.js +21 -0
- package/lib/esm/view/referralView/epics/sendReferralInviteEpic.js +9 -1
- package/lib/esm/view/referralView/referralReducer.js +3 -2
- package/lib/esm/view/spendManagement/commonSetup/setupViewReducer.js +5 -1
- package/lib/esm/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +2 -2
- package/lib/esm/view/taskManager/taskDetailView/epics/sendCommentMentionNotificationEpic.js +2 -2
- package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +1 -1
- package/lib/esm/view/taskManager/taskListView/taskListReducer.js +3 -1
- package/lib/esm/view/transactionDetail/epics/saveTransactionDetailEpic.js +3 -1
- package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +11 -2
- package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +34 -5
- package/lib/esm/view/transactionDetail/transactionDetailLocalDataHelper.js +17 -0
- package/lib/index.d.ts +14 -14
- package/lib/index.js +57 -37
- package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +14 -0
- package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +8 -4
- package/lib/view/aiCfoView/aiCfoViewReducer.js +30 -4
- package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +2 -1
- package/lib/view/aiCfoView/aiCfoViewSelector.js +12 -0
- package/lib/view/aiCfoView/aiCfoViewState.d.ts +15 -0
- package/lib/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -2
- package/lib/view/aiCfoView/epics/fetchSkillsEpic.d.ts +8 -0
- package/lib/view/aiCfoView/epics/fetchSkillsEpic.js +38 -0
- package/lib/view/aiCfoView/epics/submitQuestionEpic.js +7 -1
- package/lib/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.d.ts +6 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.js +38 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/reparseStatementEpic.d.ts +26 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/reparseStatementEpic.js +35 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.d.ts +27 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.js +61 -0
- package/lib/view/expenseAutomationView/epics/fluxAnalysis/fetchFluxAnalysisViewEpic.js +1 -0
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +47 -9
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +30 -3
- package/lib/view/expenseAutomationView/payload/fluxAnalysisPayload.d.ts +8 -0
- package/lib/view/expenseAutomationView/payload/reconciliationPayload.d.ts +176 -10
- package/lib/view/expenseAutomationView/payload/reconciliationPayload.js +159 -0
- package/lib/view/expenseAutomationView/payload/transactionCategorizationPayload.d.ts +7 -0
- package/lib/view/expenseAutomationView/reducers/fluxAnalysisViewReducer.d.ts +2 -1
- package/lib/view/expenseAutomationView/reducers/fluxAnalysisViewReducer.js +6 -1
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.d.ts +53 -3
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +190 -10
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +37 -17
- package/lib/view/expenseAutomationView/selectorTypes/reconciliationViewSelectorTypes.d.ts +7 -1
- package/lib/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +2 -1
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.d.ts +2 -0
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +29 -1
- package/lib/view/expenseAutomationView/types/fluxAnalysisViewState.d.ts +2 -0
- package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +175 -0
- package/lib/view/expenseAutomationView/types/reconciliationViewState.js +30 -0
- package/lib/view/onboardingView/cockpitView/epic/initializeOnboardingCustomerViewUpdateDataEpic.js +3 -15
- package/lib/view/onboardingView/cockpitView/onboardingCockpitViewPayload.js +2 -2
- package/lib/view/opExByVendor/opExByVendorReducer.d.ts +6 -1
- package/lib/view/opExByVendor/opExByVendorReducer.js +29 -6
- package/lib/view/opExByVendor/opExByVendorSelector.d.ts +1 -0
- package/lib/view/opExByVendor/opExByVendorSelector.js +1 -0
- package/lib/view/opExByVendor/opExByVendorState.d.ts +1 -0
- package/lib/view/opExByVendor/refreshOpExByVendorReportEpic.d.ts +17 -0
- package/lib/view/opExByVendor/refreshOpExByVendorReportEpic.js +25 -0
- package/lib/view/referralView/epics/sendReferralInviteEpic.js +9 -1
- package/lib/view/referralView/referralReducer.d.ts +1 -0
- package/lib/view/referralView/referralReducer.js +4 -3
- package/lib/view/spendManagement/commonSetup/setupViewReducer.js +5 -1
- package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +2 -2
- package/lib/view/taskManager/taskDetailView/epics/sendCommentMentionNotificationEpic.d.ts +1 -1
- package/lib/view/taskManager/taskDetailView/epics/sendCommentMentionNotificationEpic.js +1 -1
- package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +1 -1
- package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +1 -1
- package/lib/view/taskManager/taskListView/taskListReducer.js +3 -1
- package/lib/view/transactionDetail/epics/saveTransactionDetailEpic.js +3 -1
- package/lib/view/transactionDetail/epics/saveTransactionHelper.d.ts +1 -1
- package/lib/view/transactionDetail/epics/saveTransactionHelper.js +11 -2
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.d.ts +8 -0
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +36 -6
- package/lib/view/transactionDetail/transactionDetailLocalDataHelper.js +17 -0
- package/lib/view/transactionDetail/transactionDetailState.d.ts +1 -0
- package/lib/view/transactionDetail/transactionDetailTypes.d.ts +1 -0
- package/lib/view/vendorFiling1099/vendorFiling1099List/vendorFiling1099ListState.d.ts +1 -1
- package/package.json +5 -2
|
@@ -43,6 +43,17 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
43
43
|
error: undefined,
|
|
44
44
|
})
|
|
45
45
|
: { fetchState: 'Not-Started', error: undefined };
|
|
46
|
+
const monthEndChecksForPeriod = selectedPeriod != null
|
|
47
|
+
? monthEndCloseChecksState.monthEndCloseChecksByTenantId[currentTenant.tenantId]?.[toMonthYearPeriodId(selectedPeriod)]
|
|
48
|
+
: undefined;
|
|
49
|
+
const reconCheckTimeSavedHours = monthEndChecksForPeriod?.monthEndCloseCheckList?.find((check) => check.id === 'reconciliation')?.progressJson?.timeSavedHours;
|
|
50
|
+
const summaryWithTimeSaved = reconciliationViewState.summary != null
|
|
51
|
+
? {
|
|
52
|
+
...reconciliationViewState.summary,
|
|
53
|
+
timeSavedHours: reconCheckTimeSavedHours ??
|
|
54
|
+
reconciliationViewState.summary.timeSavedHours,
|
|
55
|
+
}
|
|
56
|
+
: undefined;
|
|
46
57
|
if (accountReconForMonthYearPeriod == null) {
|
|
47
58
|
return {
|
|
48
59
|
bankAccounts: [],
|
|
@@ -66,6 +77,7 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
66
77
|
selectedTab: reconciliationViewState.selectedTab,
|
|
67
78
|
monthYearPeriod: selectedPeriod,
|
|
68
79
|
selectedAccountId: reconciliationViewState.selectedAccountId,
|
|
80
|
+
statementProcessingFailed: reconciliationViewState.statementProcessingFailed,
|
|
69
81
|
statementUploadChosen: reconciliationViewState.statementUploadChosen,
|
|
70
82
|
accountReconciliationsByAccountID: {},
|
|
71
83
|
reconciliationTabsState: initialReconciliationTabsState,
|
|
@@ -115,6 +127,7 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
115
127
|
excludeAccountFetchState: reconciliationViewState.actionFetchState.excludeAccountFetch,
|
|
116
128
|
includeAccountFetchState: reconciliationViewState.actionFetchState.includeAccountFetch,
|
|
117
129
|
excludedAccountIDs: reconciliationViewState.excludedAccountIDs,
|
|
130
|
+
summary: summaryWithTimeSaved,
|
|
118
131
|
};
|
|
119
132
|
}
|
|
120
133
|
const allAccountIDs = accountReconForMonthYearPeriod.accountIDs;
|
|
@@ -239,6 +252,12 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
239
252
|
.refreshStatus,
|
|
240
253
|
statementDeleteStatus: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
|
|
241
254
|
.statementDeleteStatus,
|
|
255
|
+
statementParseStatus: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
|
|
256
|
+
.statementParseStatus,
|
|
257
|
+
reparseStatementStatus: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
|
|
258
|
+
.reparseStatementStatus,
|
|
259
|
+
statementDateConflict: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
|
|
260
|
+
.statementDateConflict,
|
|
242
261
|
statementUpdateStatus: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
|
|
243
262
|
.statementUpdateStatus,
|
|
244
263
|
statementUploadStatus: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
|
|
@@ -247,6 +266,8 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
247
266
|
.localData,
|
|
248
267
|
statementParseInProgress: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
|
|
249
268
|
.statementParseInProgress,
|
|
269
|
+
parsedStatementData: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
|
|
270
|
+
.parsedStatementData,
|
|
250
271
|
transactionFetchState: reduceAnyFetchState([
|
|
251
272
|
accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
|
|
252
273
|
.transactionFetchState,
|
|
@@ -315,6 +336,9 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
315
336
|
statementUpdateStatus: { fetchState: 'Not-Started' },
|
|
316
337
|
statementUploadStatus: { fetchState: 'Not-Started' },
|
|
317
338
|
statementDeleteStatus: { fetchState: 'Not-Started' },
|
|
339
|
+
statementParseStatus: { fetchState: 'Not-Started' },
|
|
340
|
+
reparseStatementStatus: { fetchState: 'Not-Started' },
|
|
341
|
+
statementDateConflict: null,
|
|
318
342
|
localData: {},
|
|
319
343
|
connectionInProgress: false,
|
|
320
344
|
statementParseInProgress: false,
|
|
@@ -403,6 +427,7 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
403
427
|
refreshStatus: reconciliationViewState.refreshStatus,
|
|
404
428
|
selectedTab: reconciliationViewState.selectedTab,
|
|
405
429
|
selectedDrawerAccountId: reconciliationViewState.selectedDrawerAccountId,
|
|
430
|
+
statementProcessingFailed: reconciliationViewState.statementProcessingFailed,
|
|
406
431
|
statementUploadChosen: reconciliationViewState.statementUploadChosen,
|
|
407
432
|
monthYearPeriod: selectedPeriod,
|
|
408
433
|
accountReconciliationBySectionID,
|
|
@@ -423,8 +448,10 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
|
|
|
423
448
|
excludeAccountFetchState: reconciliationViewState.actionFetchState.excludeAccountFetch,
|
|
424
449
|
includeAccountFetchState: reconciliationViewState.actionFetchState.includeAccountFetch,
|
|
425
450
|
excludedAccountIDs: reconciliationViewState.excludedAccountIDs,
|
|
451
|
+
summary: summaryWithTimeSaved,
|
|
426
452
|
};
|
|
427
453
|
});
|
|
454
|
+
export const getReparseStatementStatusByAccountId = (state, accountId) => getExpenseAutomationReconciliationView(state).accountReconciliationsByAccountID[accountId]?.reparseStatementStatus;
|
|
428
455
|
export const isAccountReconReport = (reportId) => {
|
|
429
456
|
return reportId.endsWith('reconciliation');
|
|
430
457
|
};
|
|
@@ -1,4 +1,33 @@
|
|
|
1
1
|
import { stringToUnion } from '../../../commonStateTypes/stringToUnion';
|
|
2
|
+
export function toReconciliationViewSummary(payload) {
|
|
3
|
+
return {
|
|
4
|
+
accounts: {
|
|
5
|
+
done: payload.accounts.done,
|
|
6
|
+
failed: payload.accounts.failed,
|
|
7
|
+
inProgress: payload.accounts.in_progress,
|
|
8
|
+
total: payload.accounts.total,
|
|
9
|
+
},
|
|
10
|
+
accountsToConnectCount: payload.accounts_to_connect_count,
|
|
11
|
+
autoMatched: {
|
|
12
|
+
matchedTxns: payload.auto_matched.matched_txns,
|
|
13
|
+
totalTxns: payload.auto_matched.total_txns,
|
|
14
|
+
},
|
|
15
|
+
needsReview: {
|
|
16
|
+
accountCount: payload.needs_review.account_count,
|
|
17
|
+
txnCount: payload.needs_review.txn_count,
|
|
18
|
+
},
|
|
19
|
+
timeSavedHours: 0,
|
|
20
|
+
timeSavedPercentage: payload.time_saved_percentage,
|
|
21
|
+
progressBar: payload.progress_bar != null
|
|
22
|
+
? {
|
|
23
|
+
aiPercentageShare: payload.progress_bar.ai_percentage_share,
|
|
24
|
+
completePercentage: payload.progress_bar.complete_percentage,
|
|
25
|
+
humanPercentageShare: payload.progress_bar.human_percentage_share,
|
|
26
|
+
remainingPercentage: payload.progress_bar.remaining_percentage,
|
|
27
|
+
}
|
|
28
|
+
: undefined,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
2
31
|
export const RECONCILE_ACTIONS = [
|
|
3
32
|
'reconcile',
|
|
4
33
|
'save_reconcile_for_later',
|
|
@@ -4,7 +4,7 @@ import { getAddressByAddressId } from '../../../../entity/address/addressSelecto
|
|
|
4
4
|
import { getOnboardingCompanyByCompanyId } from '../../../../entity/company/companySelector';
|
|
5
5
|
import { toAccountingConnectionCreationModeStrict } from '../../../../entity/company/companyStateTypes';
|
|
6
6
|
import { getOnboardingCustomersByCompanyId } from '../../../../entity/onboardingCustomer/onboardingCustomerSelector';
|
|
7
|
-
import { getOnboardingTenantByTenantId, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly,
|
|
7
|
+
import { getOnboardingTenantByTenantId, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly, } from '../../../../entity/tenant/tenantSelector';
|
|
8
8
|
import { getUserByUserId } from '../../../../entity/user/userSelector';
|
|
9
9
|
import { newAddressInLocalStore, resetNewAddressesInLocalStore, } from '../../../addressView/addressViewReducer';
|
|
10
10
|
import { clearOnboardingCustomerViewUpdateData, initializeOnboardingCustomerViewUpdateData, saveOnboardingCustomerDataInLocalStore, saveOnboardingCustomerViewUpdateData, updateCustomerLocalStoreInitStateOnFailure, } from '../onboardingCockpitViewReducer';
|
|
@@ -112,32 +112,20 @@ const getSelectedProducts = (isDebitCardFlagEnabled, tenant) => {
|
|
|
112
112
|
const isBookkeepingEnabled = isTenantBookkeepingEnabled(tenant);
|
|
113
113
|
const isOtherProductsEnabled = isOtherProductsEnabledForTenant(tenant);
|
|
114
114
|
const isCardsEnabled = isTenantCardsOnly(tenant);
|
|
115
|
-
const isTreasuryEnabled = isTenantTreasuryEnabled(tenant);
|
|
116
115
|
if (isCardsEnabled && isBankingOnly) {
|
|
117
|
-
|
|
118
|
-
if (isTreasuryEnabled) {
|
|
119
|
-
selectedProducts.push('zeni_treasury');
|
|
120
|
-
}
|
|
121
|
-
return selectedProducts;
|
|
116
|
+
return [];
|
|
122
117
|
}
|
|
123
118
|
else if (isBankingOnly) {
|
|
124
|
-
|
|
125
|
-
if (isTreasuryEnabled) {
|
|
126
|
-
selectedProducts.push('zeni_treasury');
|
|
127
|
-
}
|
|
128
|
-
return selectedProducts;
|
|
119
|
+
return [];
|
|
129
120
|
}
|
|
130
121
|
else if (isCardsEnabled) {
|
|
131
|
-
return [
|
|
122
|
+
return [];
|
|
132
123
|
}
|
|
133
124
|
else if (isBookkeepingEnabled) {
|
|
134
125
|
return [
|
|
135
126
|
'bookkeeping',
|
|
136
127
|
'zeni_bill_pay',
|
|
137
|
-
'zeni_checking',
|
|
138
128
|
'zeni_reimbursements',
|
|
139
|
-
'zeni_treasury',
|
|
140
|
-
'zeni_cards',
|
|
141
129
|
];
|
|
142
130
|
}
|
|
143
131
|
else if (isOtherProductsEnabled) {
|
|
@@ -48,9 +48,9 @@ export const toOnboardingCustomerPayload = (onboardingCustomer, sendInvite, comp
|
|
|
48
48
|
const isTreasury = selectedProducts.includes('zeni_treasury');
|
|
49
49
|
if (isBookkeeping) {
|
|
50
50
|
onboardingCustomerPayload.is_book_keeping_enabled = true;
|
|
51
|
-
onboardingCustomerPayload.is_banking_enabled =
|
|
51
|
+
onboardingCustomerPayload.is_banking_enabled = isChecking;
|
|
52
52
|
onboardingCustomerPayload.is_spend_management_enabled = true;
|
|
53
|
-
onboardingCustomerPayload.is_card_enabled =
|
|
53
|
+
onboardingCustomerPayload.is_card_enabled = isCards;
|
|
54
54
|
onboardingCustomerPayload.is_treasury_enabled = isTreasury;
|
|
55
55
|
}
|
|
56
56
|
else if (isChecking && isCards) {
|
|
@@ -22,6 +22,10 @@ export const initialState = {
|
|
|
22
22
|
error: undefined,
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
|
+
refreshStatus: {
|
|
26
|
+
fetchState: 'Not-Started',
|
|
27
|
+
error: undefined,
|
|
28
|
+
},
|
|
25
29
|
summaryFetchState: {
|
|
26
30
|
fetchState: 'Not-Started',
|
|
27
31
|
error: undefined,
|
|
@@ -259,12 +263,32 @@ const opexByVendor = createSlice({
|
|
|
259
263
|
[timeframe]: [],
|
|
260
264
|
};
|
|
261
265
|
},
|
|
266
|
+
refreshOpExByVendorReport(draft) {
|
|
267
|
+
draft.refreshStatus = { fetchState: 'In-Progress', error: undefined };
|
|
268
|
+
},
|
|
269
|
+
refreshOpExByVendorReportSuccess(draft, action) {
|
|
270
|
+
draft.refreshStatus = { fetchState: 'Completed', error: undefined };
|
|
271
|
+
if (action.payload.lastRefreshSuccessTime != null) {
|
|
272
|
+
draft.lastRefreshSuccessTime = action.payload.lastRefreshSuccessTime;
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
refreshOpExByVendorReportFailure: {
|
|
276
|
+
prepare(error) {
|
|
277
|
+
return { payload: { error } };
|
|
278
|
+
},
|
|
279
|
+
reducer(draft, action) {
|
|
280
|
+
draft.refreshStatus = {
|
|
281
|
+
fetchState: 'Error',
|
|
282
|
+
error: action.payload.error,
|
|
283
|
+
};
|
|
284
|
+
},
|
|
285
|
+
},
|
|
262
286
|
clearOpExByVendor(draft) {
|
|
263
287
|
Object.assign(draft, initialState);
|
|
264
288
|
},
|
|
265
289
|
},
|
|
266
290
|
});
|
|
267
|
-
export const { fetchOpExByVendor, updateOpExByVendorReportGenerated, fetchOpExByVendorReportForTimeframe, updateOpExByVendorReportFailureForTimeframe, updateOpExByVendorReportSuccessForTimeframe, fetchOpExByVendorReportSummary, updateOpExByVendorReportSummaryFailure, updateOpExByVendorReportSummarySuccess, updateOpExByVendorTimeFrame, updateOpExByVendorUIState, clearOpExByVendor, updateOpExByVendorAdditionalBalancesSelection, updateOpExByVendorSort, updateOpExByVendorSortOrSearchInProgress, updateOpExByVendorPageFetchInProgress, updateOpExByVendorDownloadState, clearOpExByVendorSearch, updateOpExByVendorPageLimit, updateOpExByVendorSearchString, } = opexByVendor.actions;
|
|
291
|
+
export const { fetchOpExByVendor, updateOpExByVendorReportGenerated, fetchOpExByVendorReportForTimeframe, updateOpExByVendorReportFailureForTimeframe, updateOpExByVendorReportSuccessForTimeframe, fetchOpExByVendorReportSummary, updateOpExByVendorReportSummaryFailure, updateOpExByVendorReportSummarySuccess, updateOpExByVendorTimeFrame, updateOpExByVendorUIState, clearOpExByVendor, updateOpExByVendorAdditionalBalancesSelection, updateOpExByVendorSort, updateOpExByVendorSortOrSearchInProgress, updateOpExByVendorPageFetchInProgress, updateOpExByVendorDownloadState, clearOpExByVendorSearch, updateOpExByVendorPageLimit, updateOpExByVendorSearchString, refreshOpExByVendorReport, refreshOpExByVendorReportSuccess, refreshOpExByVendorReportFailure, } = opexByVendor.actions;
|
|
268
292
|
export default opexByVendor.reducer;
|
|
269
293
|
const doUpdateOpexByVendorReport = (draft, timeframe, reportPayload, queryProps) => {
|
|
270
294
|
if (reportPayload.status.is_report_generated == null) {
|
|
@@ -317,10 +341,9 @@ const doUpdateOpexByVendorReportSummary = (draft, reportPayload) => {
|
|
|
317
341
|
const report = mapReportPayloadToReport(reportPayload);
|
|
318
342
|
draft.firstMonthOfFY = report.firstMonthOfFY;
|
|
319
343
|
draft.bookCloseDate = report.bookCloseDate;
|
|
320
|
-
|
|
321
|
-
reportPayload.status.last_refresh_success_time
|
|
322
|
-
|
|
323
|
-
: undefined;
|
|
344
|
+
if (reportPayload.status.last_refresh_success_time != null) {
|
|
345
|
+
draft.lastRefreshSuccessTime = date(reportPayload.status.last_refresh_success_time);
|
|
346
|
+
}
|
|
324
347
|
draft.totalOpexByVendor = combineCOABalanceGrouped(mapCOABalanceGroupedPayloadV2ToCOABalanceGrouped(reportPayload.operating_expenses, reportPayload.currency, 'month'), mapCOABalanceGroupedPayloadV2ToCOABalanceGrouped(reportPayload.operating_expenses, reportPayload.currency, 'quarter'));
|
|
325
348
|
draft.summaryOpexByVendorKey = mapVendorSummaryBalances(reportPayload.operating_expenses, reportPayload.currency);
|
|
326
349
|
}
|
|
@@ -67,6 +67,7 @@ export const getOpExByVendorReport = createSelector((state) => state.opExByVendo
|
|
|
67
67
|
filter,
|
|
68
68
|
isReportGenerated: opExByVendorState.opExByVendorReportGenerated,
|
|
69
69
|
lastRefreshSuccessTime: opExByVendorState.lastRefreshSuccessTime,
|
|
70
|
+
refreshStatus: opExByVendorState.refreshStatus,
|
|
70
71
|
opexBalances,
|
|
71
72
|
summaryBalances,
|
|
72
73
|
allTimeframeTicks,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { createZeniAPIStatus } from '../../responsePayload';
|
|
4
|
+
import { date } from '../../zeniDayJS';
|
|
5
|
+
import { refreshOpExByVendorReport, refreshOpExByVendorReportFailure, refreshOpExByVendorReportSuccess, } from './opExByVendorReducer';
|
|
6
|
+
export const refreshOpExByVendorReportEpic = (actions$, _state, zeniAPI) => actions$.pipe(filter(refreshOpExByVendorReport.match), switchMap(() => {
|
|
7
|
+
return zeniAPI
|
|
8
|
+
.postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/reports/operating-expenses-by-vendor/refresh`)
|
|
9
|
+
.pipe(mergeMap((response) => {
|
|
10
|
+
if (response.status.code >= 200 && response.status.code < 300) {
|
|
11
|
+
const lastRefreshSuccessTime = response.status.last_refresh_success_time != null
|
|
12
|
+
? date(response.status.last_refresh_success_time)
|
|
13
|
+
: undefined;
|
|
14
|
+
return of(refreshOpExByVendorReportSuccess({ lastRefreshSuccessTime }));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
return of(refreshOpExByVendorReportFailure(response.status));
|
|
18
|
+
}
|
|
19
|
+
}), catchError((error) => of(refreshOpExByVendorReportFailure(createZeniAPIStatus('Unexpected error', 'Refresh OpEx by Vendor REST API call errored out: ' +
|
|
20
|
+
JSON.stringify(error))))));
|
|
21
|
+
}));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { of } from 'rxjs';
|
|
2
2
|
import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
3
4
|
import { createZeniAPIStatus, isSuccessStatus } from '../../../responsePayload';
|
|
4
5
|
import { sendReferralInvite, sendReferralInviteFailure, sendReferralInviteSuccess, } from '../referralReducer';
|
|
5
6
|
export const sendReferralInviteEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(sendReferralInvite.match), switchMap(() => {
|
|
@@ -13,7 +14,14 @@ export const sendReferralInviteEpic = (actions$, state$, zeniAPI) => actions$.pi
|
|
|
13
14
|
.postAndGetJSON(`${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/company-referrals`, invitePayload)
|
|
14
15
|
.pipe(mergeMap((response) => {
|
|
15
16
|
if (isSuccessStatus(response)) {
|
|
16
|
-
const actions = [
|
|
17
|
+
const actions = [
|
|
18
|
+
sendReferralInviteSuccess(),
|
|
19
|
+
openSnackbar({
|
|
20
|
+
messageSection: 'referral_invite_sent',
|
|
21
|
+
messageText: 'success',
|
|
22
|
+
type: 'success',
|
|
23
|
+
}),
|
|
24
|
+
];
|
|
17
25
|
return actions;
|
|
18
26
|
}
|
|
19
27
|
else {
|
|
@@ -4,6 +4,7 @@ import { date } from '../../zeniDayJS';
|
|
|
4
4
|
import { toZeniUrl } from '../../zeniUrl';
|
|
5
5
|
import { toReferralInvitation, } from './referralPayload';
|
|
6
6
|
import { toSupportedRewardPlansType, } from './referralState';
|
|
7
|
+
export const DEFAULT_REFERRER_AMOUNT = 4000;
|
|
7
8
|
export const initialState = {
|
|
8
9
|
fetchState: 'Not-Started',
|
|
9
10
|
error: undefined,
|
|
@@ -44,7 +45,7 @@ export const initialState = {
|
|
|
44
45
|
},
|
|
45
46
|
rewardsPlan: {
|
|
46
47
|
referrerAmount: {
|
|
47
|
-
amount:
|
|
48
|
+
amount: DEFAULT_REFERRER_AMOUNT,
|
|
48
49
|
currencyCode: 'USD',
|
|
49
50
|
currencySymbol: '$',
|
|
50
51
|
},
|
|
@@ -53,7 +54,7 @@ export const initialState = {
|
|
|
53
54
|
currencyCode: 'USD',
|
|
54
55
|
currencySymbol: '$',
|
|
55
56
|
},
|
|
56
|
-
planName: '
|
|
57
|
+
planName: 'PLAN_4000',
|
|
57
58
|
planId: 'dummy',
|
|
58
59
|
referralLink: toZeniUrl(''),
|
|
59
60
|
},
|
|
@@ -111,7 +111,11 @@ const setupView = createSlice({
|
|
|
111
111
|
saveSetupViewDataInLocalStore(draft, action) {
|
|
112
112
|
const setupViewLocalData = action.payload;
|
|
113
113
|
if (setupViewLocalData.companyDetails != null) {
|
|
114
|
-
|
|
114
|
+
const syncToken = setupViewLocalData.companyDetails.syncToken ?? draft.companyDetails.localData?.syncToken;
|
|
115
|
+
draft.companyDetails.localData = {
|
|
116
|
+
...setupViewLocalData.companyDetails,
|
|
117
|
+
...(syncToken != null ? { syncToken } : {}),
|
|
118
|
+
};
|
|
115
119
|
}
|
|
116
120
|
if (setupViewLocalData.primaryContactDetails != null) {
|
|
117
121
|
draft.primaryContactDetails.localData =
|
|
@@ -16,8 +16,8 @@ export const saveTaskDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(f
|
|
|
16
16
|
// fall back to the entity's current group. For a create, use the
|
|
17
17
|
// taskGroupId from the action payload.
|
|
18
18
|
const localTaskGroupId = taskId != null
|
|
19
|
-
? state.taskDetailState.editTaskStateById[taskId]
|
|
20
|
-
|
|
19
|
+
? state.taskDetailState.editTaskStateById[taskId]
|
|
20
|
+
?.taskDetailLocalData?.taskGroupId
|
|
21
21
|
: undefined;
|
|
22
22
|
// Distinguish three cases (PR #3101 review):
|
|
23
23
|
// - create (taskId == null): use the action payload group.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createAction } from '@reduxjs/toolkit';
|
|
2
|
-
import { EMPTY
|
|
2
|
+
import { EMPTY } from 'rxjs';
|
|
3
3
|
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
4
4
|
/**
|
|
5
5
|
* Fire-and-forget action — dispatched by the task-comments UI when a comment
|
|
@@ -33,5 +33,5 @@ const handleSendCommentMentionNotification = ({ taskId, mentionedUserIds, perfor
|
|
|
33
33
|
// non-success responses and network errors so a Slack outage
|
|
34
34
|
// does not pollute the dev console for every @-mention.
|
|
35
35
|
return EMPTY;
|
|
36
|
-
}), catchError(() =>
|
|
36
|
+
}), catchError(() => EMPTY));
|
|
37
37
|
};
|
|
@@ -32,7 +32,7 @@ export const getTaskDetail = (state, taskId) => {
|
|
|
32
32
|
const taskEntity = getTaskById(taskState, taskId);
|
|
33
33
|
subtasks =
|
|
34
34
|
taskEntity != null
|
|
35
|
-
? getTasksByIds(taskState, taskEntity.subTasksIds)
|
|
35
|
+
? getTasksByIds(taskState, taskEntity.subTasksIds ?? [])
|
|
36
36
|
: [];
|
|
37
37
|
const fileIdsInEntity = taskEntity?.fileIds ?? [];
|
|
38
38
|
if (taskEntity != null) {
|
|
@@ -490,7 +490,9 @@ const taskList = createSlice({
|
|
|
490
490
|
// never move between tabs on their own.
|
|
491
491
|
builder.addCase(updateTasks, (draft, action) => {
|
|
492
492
|
action.payload.forEach((taskPayload) => {
|
|
493
|
-
|
|
493
|
+
// Only re-bucket parents; subtasks (parent_task_id is a non-empty
|
|
494
|
+
// string) are nested under their parent row and don't move tabs.
|
|
495
|
+
if (taskPayload.parent_task_id !== null && taskPayload.parent_task_id !== undefined && taskPayload.parent_task_id !== '') {
|
|
494
496
|
return;
|
|
495
497
|
}
|
|
496
498
|
const taskId = taskPayload.task_id;
|
|
@@ -2,6 +2,7 @@ import recordGet from 'lodash/get';
|
|
|
2
2
|
import { from } from 'rxjs';
|
|
3
3
|
import { filter, mergeMap } from 'rxjs/operators';
|
|
4
4
|
import { getSupportedTransactionById } from '../../../entity/transaction/transactionSelector';
|
|
5
|
+
import { getIsAccountingProjectsEnabled } from '../../../entity/tenant/tenantSelector';
|
|
5
6
|
import { saveTransactionDetail, updateTransactionDetail, } from '../transactionDetailReducer';
|
|
6
7
|
import { getTransactionDetailKey } from '../transactionDetailState';
|
|
7
8
|
import { toTransactionUpdatesFromTransactionDetailLocalData } from './saveTransactionHelper';
|
|
@@ -10,12 +11,13 @@ export const saveTransactionDetailEpic = (actions$, state$) => actions$.pipe(fil
|
|
|
10
11
|
const fetchActions = [];
|
|
11
12
|
const transactionDetailState = state$.value.transactionDetailState;
|
|
12
13
|
const transactionState = state$.value.transactionState;
|
|
14
|
+
const isAccountingProjectsEnabled = getIsAccountingProjectsEnabled(state$.value);
|
|
13
15
|
const key = getTransactionDetailKey(transactionId);
|
|
14
16
|
const detail = recordGet(transactionDetailState.transactionDetailById, key, undefined);
|
|
15
17
|
const transaction = getSupportedTransactionById(transactionState, key);
|
|
16
18
|
if (detail != null && transaction != null) {
|
|
17
19
|
const localData = detail.transactionDetailLocalData;
|
|
18
|
-
const transactionSaveUpdates = toTransactionUpdatesFromTransactionDetailLocalData(localData, transaction, isExpenseAutomationEnabled);
|
|
20
|
+
const transactionSaveUpdates = toTransactionUpdatesFromTransactionDetailLocalData(localData, transaction, isExpenseAutomationEnabled, isAccountingProjectsEnabled);
|
|
19
21
|
fetchActions.push(updateTransactionDetail(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking, isUncategorizedExpenseCategoryEnabled));
|
|
20
22
|
return from(fetchActions);
|
|
21
23
|
}
|
|
@@ -21,7 +21,7 @@ import { isAccountUncategorized } from '../transactionDetailLocalDataHelper';
|
|
|
21
21
|
* 4. Only difference between this and Miscategorized will be that we will
|
|
22
22
|
* additionally fire “Mark as not miscat” for every point above.
|
|
23
23
|
*/
|
|
24
|
-
export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLocalData, transaction, isExpenseAutomationEnabled) => {
|
|
24
|
+
export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDetailLocalData, transaction, isExpenseAutomationEnabled, isAccountingProjectsEnabled = false) => {
|
|
25
25
|
const updates = {
|
|
26
26
|
updatesByLineId: {},
|
|
27
27
|
};
|
|
@@ -30,6 +30,12 @@ export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDe
|
|
|
30
30
|
const isTransactionMisCategorized = isTransactionMiscategorized(transaction, isExpenseAutomationEnabled);
|
|
31
31
|
updates.memo = transactionDetailLocalData.memo;
|
|
32
32
|
updates.documentId = transactionDetailLocalData.documentId;
|
|
33
|
+
// Project is at the transaction level only for invoice and credit_memo,
|
|
34
|
+
// and only when the projects feature is enabled for this tenant.
|
|
35
|
+
if (isAccountingProjectsEnabled &&
|
|
36
|
+
(transaction.type === 'invoice' || transaction.type === 'credit_memo')) {
|
|
37
|
+
updates.project = transactionDetailLocalData.project;
|
|
38
|
+
}
|
|
33
39
|
const selectedEntity = transactionDetailLocalData.selectedEntity;
|
|
34
40
|
const updatedEntityId = transactionDetailLocalData.updatePreviousTransactionsWithUpdatedVendor ===
|
|
35
41
|
true
|
|
@@ -52,7 +58,10 @@ export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDe
|
|
|
52
58
|
lineDescription: lineItem.lineDescription,
|
|
53
59
|
class: lineItem.class,
|
|
54
60
|
account: lineItem.account,
|
|
55
|
-
|
|
61
|
+
// Project is at the transaction level for invoice/credit_memo; omit from lines.
|
|
62
|
+
...(transaction.type !== 'invoice' && transaction.type !== 'credit_memo'
|
|
63
|
+
? { project: lineItem.project }
|
|
64
|
+
: {}),
|
|
56
65
|
recommendation: convertCOTRecommendationsToRegular(lineItem.recommendationsWithCOT),
|
|
57
66
|
};
|
|
58
67
|
if (line.type === 'journal_entry_transaction_line' ||
|
|
@@ -19,6 +19,7 @@ import { getSupportedTransactionById } from '../../../entity/transaction/transac
|
|
|
19
19
|
import { updateVendors } from '../../../entity/vendor/vendorReducer';
|
|
20
20
|
import { getVendorByVendorId } from '../../../entity/vendor/vendorSelector';
|
|
21
21
|
import { createZeniAPIStatus, isActionNotAllowed, isSuccessResponse, } from '../../../responsePayload';
|
|
22
|
+
import { getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, } from '../../../entity/tenant/tenantSelector';
|
|
22
23
|
import { getUncategorizedAccounts } from '../../accountList/accountListSelector';
|
|
23
24
|
import { getPendingReviewLineIdsFromTransaction } from '../../expenseAutomationView/helpers/transactionCategorizationLocalDataHelper';
|
|
24
25
|
import { syncTransactionCategorizationFromDetailSave } from '../../expenseAutomationView/reducers/transactionsViewReducer';
|
|
@@ -27,9 +28,10 @@ import { getTransactionDetailKey, } from '../transactionDetailState';
|
|
|
27
28
|
import { isTransactionUncategorized } from './saveTransactionHelper';
|
|
28
29
|
export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(updateTransactionDetail.match), mergeMap((action) => {
|
|
29
30
|
const { transactionState, vendorState, transactionDetailState } = state$.value;
|
|
31
|
+
const isAccountingProjectsEnabled = getIsAccountingProjectsEnabled(state$.value);
|
|
30
32
|
const { cotTransactionTracking, transactionId, transactionSaveUpdates, isUncategorizedExpenseCategoryEnabled, } = action.payload;
|
|
31
33
|
return zeniAPI
|
|
32
|
-
.putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${action.payload.transactionId.id}/categorize`, preparePayload(transactionState, vendorState, transactionDetailState, transactionId, transactionSaveUpdates, cotTransactionTracking))
|
|
34
|
+
.putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${action.payload.transactionId.id}/categorize`, preparePayload(transactionState, vendorState, transactionDetailState, transactionId, transactionSaveUpdates, cotTransactionTracking, isAccountingProjectsEnabled))
|
|
33
35
|
.pipe(mergeMap((response) => {
|
|
34
36
|
if (isSuccessResponse(response) && response.data != null) {
|
|
35
37
|
const transactionIdResp = toTransactionID(response.data.transaction);
|
|
@@ -67,7 +69,9 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
|
|
|
67
69
|
// then we need to skip mark-miscategorized-as-correct api call
|
|
68
70
|
if (toVendorTransactionTypeStrict(response.data.transaction.transaction_type) != null ||
|
|
69
71
|
toJEAndDepositTransactionTypeStrict(response.data.transaction.transaction_type) != null) {
|
|
70
|
-
const
|
|
72
|
+
const isAccountingClassesEnabled = getIsAccountingClassesEnabled(state$.value);
|
|
73
|
+
const isAnyClassMissing = isAccountingClassesEnabled &&
|
|
74
|
+
checkIfClassMissingForAnyLineItem(response.data.transaction);
|
|
71
75
|
const isVendorOrCustomerMissingInAnyLine = toJEAndDepositTransactionTypeStrict(response.data.transaction.transaction_type) != null &&
|
|
72
76
|
checkIfVendorOrCustomerMissingForAnyLineItem(response.data.transaction);
|
|
73
77
|
if ((vendorUpdates?.id == null &&
|
|
@@ -123,7 +127,7 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
|
|
|
123
127
|
}
|
|
124
128
|
}), catchError((error) => of(updateTransactionDetailSaveStatus(action.payload.transactionId, 'Error', createZeniAPIStatus('Unexpected Error', `REST API call errored out ${error}`)))));
|
|
125
129
|
}));
|
|
126
|
-
function preparePayload(transactionState, vendorState, transactionDetailState, transactionId, saveUpdates, cotTransactionTracking) {
|
|
130
|
+
function preparePayload(transactionState, vendorState, transactionDetailState, transactionId, saveUpdates, cotTransactionTracking, isAccountingProjectsEnabled) {
|
|
127
131
|
const transactionDetailKey = getTransactionDetailKey(transactionId);
|
|
128
132
|
const detail = getSupportedTransactionById(transactionState, transactionDetailKey);
|
|
129
133
|
const tranDetail = recordGet(transactionDetailState.transactionDetailById, transactionDetailKey, undefined);
|
|
@@ -155,7 +159,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
155
159
|
};
|
|
156
160
|
}
|
|
157
161
|
if (detail != null) {
|
|
158
|
-
const transUpdates = toTransactionUpdatePayload(saveUpdates.updates, detail, cotTransactionTracking, vendorUpdates, customerUpdates, currentSelectedEntity);
|
|
162
|
+
const transUpdates = toTransactionUpdatePayload(saveUpdates.updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, currentSelectedEntity);
|
|
159
163
|
const entityUpdates = toEntityUpdatePayload(saveUpdates.entityRelatedUpdates);
|
|
160
164
|
return {
|
|
161
165
|
entity_related_updates: entityUpdates,
|
|
@@ -165,7 +169,7 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
|
|
|
165
169
|
}
|
|
166
170
|
return undefined;
|
|
167
171
|
}
|
|
168
|
-
const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, vendorUpdates, customerUpdates, tranSelectedEntity) => {
|
|
172
|
+
export const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, isAccountingProjectsEnabled, vendorUpdates, customerUpdates, tranSelectedEntity) => {
|
|
169
173
|
const transaction = Object.assign({}, detail);
|
|
170
174
|
transaction.memo = updates.memo ?? '';
|
|
171
175
|
// Unlike `memo` (always reset to '' when absent), `documentId` falls back to
|
|
@@ -226,6 +230,31 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, ven
|
|
|
226
230
|
let basePayload;
|
|
227
231
|
if (isCustomerTransaction(transaction)) {
|
|
228
232
|
basePayload = toCustomerTransactionPayload(transaction);
|
|
233
|
+
// For invoice/credit_memo only, project lives at the transaction level.
|
|
234
|
+
// Guard behind the projects feature flag to avoid touching the field when
|
|
235
|
+
// projects are disabled for this tenant. Clear-project (null injection) is
|
|
236
|
+
// intentionally out of scope for this change — the null write-back path will
|
|
237
|
+
// be added in a follow-up once the backend contract is confirmed.
|
|
238
|
+
if (isAccountingProjectsEnabled &&
|
|
239
|
+
(transaction.type === 'invoice' || transaction.type === 'credit_memo') &&
|
|
240
|
+
updates.project != null) {
|
|
241
|
+
basePayload = {
|
|
242
|
+
...basePayload,
|
|
243
|
+
accounting_project_id: updates.project.projectId,
|
|
244
|
+
// Only spread integration_id / name when we have a concrete value; omitting
|
|
245
|
+
// them avoids accidentally nulling/blanking out the server-side value when
|
|
246
|
+
// the load path didn't surface the field (e.g. list-shaped data or pre-deploy
|
|
247
|
+
// store where the API returned projectId but not the name/integration_id).
|
|
248
|
+
...(updates.project.accountingProviderProjectId != null
|
|
249
|
+
? {
|
|
250
|
+
accounting_project_integration_id: updates.project.accountingProviderProjectId,
|
|
251
|
+
}
|
|
252
|
+
: {}),
|
|
253
|
+
...(updates.project.projectName
|
|
254
|
+
? { accounting_project_name: updates.project.projectName }
|
|
255
|
+
: {}),
|
|
256
|
+
};
|
|
257
|
+
}
|
|
229
258
|
}
|
|
230
259
|
else if (isVendorTransaction(transaction)) {
|
|
231
260
|
if (tranSelectedEntity != null && tranSelectedEntity.type === 'customer') {
|
|
@@ -12,6 +12,17 @@ export const toTransactionDetailLocalData = (transaction, defaultVendorId, uncat
|
|
|
12
12
|
const vendorId = defaultVendorId ?? transaction.vendor?.id;
|
|
13
13
|
transactionLocal.memo = transaction.memo;
|
|
14
14
|
transactionLocal.documentId = transaction.documentId;
|
|
15
|
+
// Project is at the transaction level only for invoice and credit_memo.
|
|
16
|
+
if ((transaction.type === 'invoice' || transaction.type === 'credit_memo') &&
|
|
17
|
+
transaction.projectId != null) {
|
|
18
|
+
transactionLocal.project = {
|
|
19
|
+
projectId: transaction.projectId,
|
|
20
|
+
projectName: transaction.projectName ?? '',
|
|
21
|
+
...(transaction.accountingProviderProjectId != null
|
|
22
|
+
? { accountingProviderProjectId: transaction.accountingProviderProjectId }
|
|
23
|
+
: {}),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
15
26
|
transactionLocal.vendorUpdates =
|
|
16
27
|
isVendorTransaction(transaction) && vendorId != null
|
|
17
28
|
? {
|
|
@@ -423,6 +434,7 @@ export const toUpdateLineItemsOriginalCategoryClass = (transaction, transactionD
|
|
|
423
434
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
424
435
|
memo: transactionDetailLocalData.memo,
|
|
425
436
|
documentId: transactionDetailLocalData.documentId,
|
|
437
|
+
project: transactionDetailLocalData.project,
|
|
426
438
|
lineItemById: newLineItems,
|
|
427
439
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
428
440
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
@@ -527,6 +539,7 @@ export const toSetAllLineItemsToCategoryClass = (transaction, transactionDetailL
|
|
|
527
539
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
528
540
|
memo: transactionDetailLocalData.memo,
|
|
529
541
|
documentId: transactionDetailLocalData.documentId,
|
|
542
|
+
project: transactionDetailLocalData.project,
|
|
530
543
|
lineItemById: newLineItems,
|
|
531
544
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
532
545
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
@@ -572,6 +585,7 @@ export const toSetAllLineItemsLocalDataIsUpdateAllChecked = (transaction, transa
|
|
|
572
585
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
573
586
|
memo: transactionDetailLocalData.memo,
|
|
574
587
|
documentId: transactionDetailLocalData.documentId,
|
|
588
|
+
project: transactionDetailLocalData.project,
|
|
575
589
|
lineItemById: newLineItems,
|
|
576
590
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
577
591
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
@@ -729,6 +743,7 @@ export const setEntityRecommendationForLineIdInLocalData = (transaction, transac
|
|
|
729
743
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
730
744
|
memo: transactionDetailLocalData.memo,
|
|
731
745
|
documentId: transactionDetailLocalData.documentId,
|
|
746
|
+
project: transactionDetailLocalData.project,
|
|
732
747
|
lineItemById: newLineItems,
|
|
733
748
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
734
749
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
@@ -782,6 +797,7 @@ export const removeEntityRecommendationForLineIdInLocalData = (transaction, tran
|
|
|
782
797
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
783
798
|
memo: transactionDetailLocalData.memo,
|
|
784
799
|
documentId: transactionDetailLocalData.documentId,
|
|
800
|
+
project: transactionDetailLocalData.project,
|
|
785
801
|
lineItemById: newLineItems,
|
|
786
802
|
vendorDetails: transactionDetailLocalData.vendorDetails,
|
|
787
803
|
vendorUpdates: transactionDetailLocalData.vendorUpdates,
|
|
@@ -1002,6 +1018,7 @@ export const toUpdateLineItemsToOriginalVendor = (transaction, transactionDetail
|
|
|
1002
1018
|
...initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
1003
1019
|
memo: transactionDetailLocalData.memo,
|
|
1004
1020
|
documentId: transactionDetailLocalData.documentId,
|
|
1021
|
+
project: transactionDetailLocalData.project,
|
|
1005
1022
|
lineItemById: newLineItems,
|
|
1006
1023
|
isVendorUpdateAllChecked: false,
|
|
1007
1024
|
latestUpdatedLineWithEntity: transactionDetailLocalData.latestUpdatedLineWithEntity,
|