@zeniai/client-epic-state 5.3.7 → 5.3.8

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.
Files changed (26) hide show
  1. package/lib/entity/invoicing/invoice/invoicePayload.d.ts +1 -0
  2. package/lib/entity/invoicing/invoice/invoicePayload.js +3 -0
  3. package/lib/entity/invoicing/invoice/invoiceState.d.ts +2 -0
  4. package/lib/entity/tenant/epic/fetchAllTenantsEpic.js +45 -38
  5. package/lib/esm/entity/invoicing/invoice/invoicePayload.js +3 -0
  6. package/lib/esm/entity/tenant/epic/fetchAllTenantsEpic.js +46 -39
  7. package/lib/esm/index.js +2 -2
  8. package/lib/esm/init.js +14 -3
  9. package/lib/esm/sessionEndpointsLoader.js +7 -0
  10. package/lib/esm/view/expenseAutomationView/epics/accountRecon/fetchReconciliationViewEpic.js +2 -1
  11. package/lib/esm/view/transactionDetail/createTransaction/createTransactionPayload.js +14 -2
  12. package/lib/esm/view/transactionDetail/createTransaction/createTransactionSelector.js +21 -2
  13. package/lib/index.d.ts +3 -2
  14. package/lib/index.js +53 -51
  15. package/lib/init.d.ts +9 -0
  16. package/lib/init.js +17 -4
  17. package/lib/sessionEndpointsLoader.d.ts +9 -0
  18. package/lib/sessionEndpointsLoader.js +11 -0
  19. package/lib/view/expenseAutomationView/epics/accountRecon/fetchReconciliationViewEpic.js +2 -1
  20. package/lib/view/transactionDetail/createTransaction/createTransactionPayload.d.ts +10 -6
  21. package/lib/view/transactionDetail/createTransaction/createTransactionPayload.js +14 -2
  22. package/lib/view/transactionDetail/createTransaction/createTransactionSelector.d.ts +4 -1
  23. package/lib/view/transactionDetail/createTransaction/createTransactionSelector.js +21 -2
  24. package/lib/view/transactionDetail/createTransaction/createTransactionState.d.ts +1 -1
  25. package/lib/zeniAPI.d.ts +2 -2
  26. package/package.json +1 -1
@@ -12,6 +12,7 @@ export interface InvoicingLineItemPayload {
12
12
  discount_amount?: number;
13
13
  entity_description?: string;
14
14
  entity_type?: string;
15
+ gross_amount?: number | null;
15
16
  id?: string;
16
17
  is_taxed?: boolean;
17
18
  item_level_discount_amount?: number;
@@ -17,6 +17,9 @@ const mapLineItem = (payload, currencyCode, currencySymbol) => ({
17
17
  : undefined,
18
18
  entityDescription: payload.entity_description,
19
19
  entityType: payload.entity_type,
20
+ grossAmount: payload.gross_amount != null
21
+ ? (0, amount_1.toAmount)(payload.gross_amount, currencyCode, currencySymbol)
22
+ : undefined,
20
23
  id: payload.id,
21
24
  isTaxed: payload.is_taxed,
22
25
  itemLevelDiscountAmount: payload.item_level_discount_amount != null
@@ -13,6 +13,8 @@ export interface InvoicingLineItem {
13
13
  discountAmount?: Amount;
14
14
  entityDescription?: string;
15
15
  entityType?: string;
16
+ /** Price before item-level coupons (`amount` is after); absent on older invoices. */
17
+ grossAmount?: Amount;
16
18
  id?: ID;
17
19
  isTaxed?: boolean;
18
20
  itemLevelDiscountAmount?: Amount;
@@ -5,6 +5,7 @@ const rxjs_1 = require("rxjs");
5
5
  const operators_1 = require("rxjs/operators");
6
6
  const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
7
7
  const responsePayload_1 = require("../../../responsePayload");
8
+ const sessionEndpointsLoader_1 = require("../../../sessionEndpointsLoader");
8
9
  const expenseAutomationViewReducer_1 = require("../../../view/expenseAutomationView/expenseAutomationViewReducer");
9
10
  const zeniDayJS_1 = require("../../../zeniDayJS");
10
11
  const companyReducer_1 = require("../../company/companyReducer");
@@ -13,48 +14,54 @@ const fetchAllTenantsEpic = (actions$, state, zeniAPI) => {
13
14
  const queryParam = {
14
15
  is_include_companies_in_response: true,
15
16
  };
16
- return actions$.pipe((0, operators_1.filter)(tenantReducer_1.fetchAllTenants.match), (0, operators_1.switchMap)((action) => zeniAPI
17
- .getJSON(`${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/users/${action.payload.userId}/tenants?query=${encodeURIComponent(JSON.stringify(queryParam))}`, Object.assign({ 'zeni-user-id': action.payload.userId }, { 'zeni-tenant-id': '' }, action.payload.zeniSessionId != null
18
- ? { 'zeni-session-id': action.payload.zeniSessionId }
19
- : {}))
20
- .pipe((0, operators_1.mergeMap)((response) => {
21
- const currentTenantId = state.value.tenantState.currentTenantId;
22
- if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
23
- const defaultSelectedPeriodsForTenants = (0, exports.getDefaultSelectedPeriodsForTenants)(response.data);
24
- let actions = [
25
- (0, tenantReducer_1.updateTenantsSuccess)(response.data),
26
- (0, expenseAutomationViewReducer_1.initializeSelectedPeriodForTenants)({
27
- selectedPeriodByTenantId: defaultSelectedPeriodsForTenants,
28
- }),
29
- ];
30
- if (response.data.companies != null) {
31
- let companiesPayload = response.data.companies;
32
- if (currentTenantId != null) {
33
- // filter out this tenant ID related company detail
34
- // Find companyID for this tenant
35
- const currentTenantPayload = response.data.tenants.find((tenant) => tenant.tenant_id === currentTenantId);
36
- if (currentTenantPayload != null) {
37
- companiesPayload = response.data.companies.filter((company) => company.company_id !== currentTenantPayload.company_id);
38
- }
39
- else {
40
- console.warn('Selected tenant record not found in response', currentTenantId);
41
- }
42
- }
43
- actions = [
44
- (0, companyReducer_1.updateCompanies)({
45
- payload: companiesPayload,
46
- schema: {},
17
+ return actions$.pipe((0, operators_1.filter)(tenantReducer_1.fetchAllTenants.match), (0, operators_1.switchMap)((action) => {
18
+ const fetchTenants$ = (0, rxjs_1.defer)(() => zeniAPI.getJSON(`${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/users/${action.payload.userId}/tenants?query=${encodeURIComponent(JSON.stringify(queryParam))}`, Object.assign({ 'zeni-user-id': action.payload.userId }, { 'zeni-tenant-id': '' }, action.payload.zeniSessionId != null
19
+ ? { 'zeni-session-id': action.payload.zeniSessionId }
20
+ : {}))).pipe((0, operators_1.mergeMap)((response) => {
21
+ const currentTenantId = state.value.tenantState.currentTenantId;
22
+ if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
23
+ const defaultSelectedPeriodsForTenants = (0, exports.getDefaultSelectedPeriodsForTenants)(response.data);
24
+ let actions = [
25
+ (0, tenantReducer_1.updateTenantsSuccess)(response.data),
26
+ (0, expenseAutomationViewReducer_1.initializeSelectedPeriodForTenants)({
27
+ selectedPeriodByTenantId: defaultSelectedPeriodsForTenants,
47
28
  }),
48
- ...actions,
49
29
  ];
30
+ if (response.data.companies != null) {
31
+ let companiesPayload = response.data.companies;
32
+ if (currentTenantId != null) {
33
+ // filter out this tenant ID related company detail
34
+ // Find companyID for this tenant
35
+ const currentTenantPayload = response.data.tenants.find((tenant) => tenant.tenant_id === currentTenantId);
36
+ if (currentTenantPayload != null) {
37
+ companiesPayload = response.data.companies.filter((company) => company.company_id !== currentTenantPayload.company_id);
38
+ }
39
+ else {
40
+ console.warn('Selected tenant record not found in response', currentTenantId);
41
+ }
42
+ }
43
+ actions = [
44
+ (0, companyReducer_1.updateCompanies)({
45
+ payload: companiesPayload,
46
+ schema: {},
47
+ }),
48
+ ...actions,
49
+ ];
50
+ }
51
+ return (0, rxjs_1.from)(actions);
50
52
  }
51
- return (0, rxjs_1.from)(actions);
52
- }
53
- else {
54
- return (0, rxjs_1.of)((0, tenantReducer_1.updateTenantsFailure)(response.status));
53
+ else {
54
+ return (0, rxjs_1.of)((0, tenantReducer_1.updateTenantsFailure)(response.status));
55
+ }
56
+ }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, tenantReducer_1.updateTenantsFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected error', 'Fetch All Tenants REST API call errored out' +
57
+ JSON.stringify(error))))));
58
+ const sessionEndpointsLoader = (0, sessionEndpointsLoader_1.getSessionEndpointsLoader)();
59
+ if (sessionEndpointsLoader == null) {
60
+ return fetchTenants$;
55
61
  }
56
- }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, tenantReducer_1.updateTenantsFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected error', 'Fetch All Tenants REST API call errored out' +
57
- JSON.stringify(error))))))));
62
+ return (0, rxjs_1.defer)(() => (0, rxjs_1.from)(sessionEndpointsLoader(action.payload.userId, action.payload.zeniSessionId))).pipe((0, operators_1.switchMap)(() => fetchTenants$), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, tenantReducer_1.updateTenantsFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected error', 'Loading session endpoints errored out: ' +
63
+ JSON.stringify(error))))));
64
+ }));
58
65
  };
59
66
  exports.fetchAllTenantsEpic = fetchAllTenantsEpic;
60
67
  exports.defaultMonthYearPeriod = {
@@ -14,6 +14,9 @@ const mapLineItem = (payload, currencyCode, currencySymbol) => ({
14
14
  : undefined,
15
15
  entityDescription: payload.entity_description,
16
16
  entityType: payload.entity_type,
17
+ grossAmount: payload.gross_amount != null
18
+ ? toAmount(payload.gross_amount, currencyCode, currencySymbol)
19
+ : undefined,
17
20
  id: payload.id,
18
21
  isTaxed: payload.is_taxed,
19
22
  itemLevelDiscountAmount: payload.item_level_discount_amount != null
@@ -1,7 +1,8 @@
1
- import { from, of } from 'rxjs';
1
+ import { defer, from, of } from 'rxjs';
2
2
  import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
3
  import { toMonth } from '../../../commonStateTypes/timePeriod';
4
4
  import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
5
+ import { getSessionEndpointsLoader } from '../../../sessionEndpointsLoader';
5
6
  import { initializeSelectedPeriodForTenants } from '../../../view/expenseAutomationView/expenseAutomationViewReducer';
6
7
  import { date, dateNow } from '../../../zeniDayJS';
7
8
  import { updateCompanies } from '../../company/companyReducer';
@@ -10,48 +11,54 @@ export const fetchAllTenantsEpic = (actions$, state, zeniAPI) => {
10
11
  const queryParam = {
11
12
  is_include_companies_in_response: true,
12
13
  };
13
- return actions$.pipe(filter(fetchAllTenants.match), switchMap((action) => zeniAPI
14
- .getJSON(`${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/users/${action.payload.userId}/tenants?query=${encodeURIComponent(JSON.stringify(queryParam))}`, Object.assign({ 'zeni-user-id': action.payload.userId }, { 'zeni-tenant-id': '' }, action.payload.zeniSessionId != null
15
- ? { 'zeni-session-id': action.payload.zeniSessionId }
16
- : {}))
17
- .pipe(mergeMap((response) => {
18
- const currentTenantId = state.value.tenantState.currentTenantId;
19
- if (isSuccessResponse(response) && response.data != null) {
20
- const defaultSelectedPeriodsForTenants = getDefaultSelectedPeriodsForTenants(response.data);
21
- let actions = [
22
- updateTenantsSuccess(response.data),
23
- initializeSelectedPeriodForTenants({
24
- selectedPeriodByTenantId: defaultSelectedPeriodsForTenants,
25
- }),
26
- ];
27
- if (response.data.companies != null) {
28
- let companiesPayload = response.data.companies;
29
- if (currentTenantId != null) {
30
- // filter out this tenant ID related company detail
31
- // Find companyID for this tenant
32
- const currentTenantPayload = response.data.tenants.find((tenant) => tenant.tenant_id === currentTenantId);
33
- if (currentTenantPayload != null) {
34
- companiesPayload = response.data.companies.filter((company) => company.company_id !== currentTenantPayload.company_id);
35
- }
36
- else {
37
- console.warn('Selected tenant record not found in response', currentTenantId);
38
- }
39
- }
40
- actions = [
41
- updateCompanies({
42
- payload: companiesPayload,
43
- schema: {},
14
+ return actions$.pipe(filter(fetchAllTenants.match), switchMap((action) => {
15
+ const fetchTenants$ = defer(() => zeniAPI.getJSON(`${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/users/${action.payload.userId}/tenants?query=${encodeURIComponent(JSON.stringify(queryParam))}`, Object.assign({ 'zeni-user-id': action.payload.userId }, { 'zeni-tenant-id': '' }, action.payload.zeniSessionId != null
16
+ ? { 'zeni-session-id': action.payload.zeniSessionId }
17
+ : {}))).pipe(mergeMap((response) => {
18
+ const currentTenantId = state.value.tenantState.currentTenantId;
19
+ if (isSuccessResponse(response) && response.data != null) {
20
+ const defaultSelectedPeriodsForTenants = getDefaultSelectedPeriodsForTenants(response.data);
21
+ let actions = [
22
+ updateTenantsSuccess(response.data),
23
+ initializeSelectedPeriodForTenants({
24
+ selectedPeriodByTenantId: defaultSelectedPeriodsForTenants,
44
25
  }),
45
- ...actions,
46
26
  ];
27
+ if (response.data.companies != null) {
28
+ let companiesPayload = response.data.companies;
29
+ if (currentTenantId != null) {
30
+ // filter out this tenant ID related company detail
31
+ // Find companyID for this tenant
32
+ const currentTenantPayload = response.data.tenants.find((tenant) => tenant.tenant_id === currentTenantId);
33
+ if (currentTenantPayload != null) {
34
+ companiesPayload = response.data.companies.filter((company) => company.company_id !== currentTenantPayload.company_id);
35
+ }
36
+ else {
37
+ console.warn('Selected tenant record not found in response', currentTenantId);
38
+ }
39
+ }
40
+ actions = [
41
+ updateCompanies({
42
+ payload: companiesPayload,
43
+ schema: {},
44
+ }),
45
+ ...actions,
46
+ ];
47
+ }
48
+ return from(actions);
47
49
  }
48
- return from(actions);
49
- }
50
- else {
51
- return of(updateTenantsFailure(response.status));
50
+ else {
51
+ return of(updateTenantsFailure(response.status));
52
+ }
53
+ }), catchError((error) => of(updateTenantsFailure(createZeniAPIStatus('Unexpected error', 'Fetch All Tenants REST API call errored out' +
54
+ JSON.stringify(error))))));
55
+ const sessionEndpointsLoader = getSessionEndpointsLoader();
56
+ if (sessionEndpointsLoader == null) {
57
+ return fetchTenants$;
52
58
  }
53
- }), catchError((error) => of(updateTenantsFailure(createZeniAPIStatus('Unexpected error', 'Fetch All Tenants REST API call errored out' +
54
- JSON.stringify(error))))))));
59
+ return defer(() => from(sessionEndpointsLoader(action.payload.userId, action.payload.zeniSessionId))).pipe(switchMap(() => fetchTenants$), catchError((error) => of(updateTenantsFailure(createZeniAPIStatus('Unexpected error', 'Loading session endpoints errored out: ' +
60
+ JSON.stringify(error))))));
61
+ }));
55
62
  };
56
63
  export const defaultMonthYearPeriod = {
57
64
  month: toMonth(dateNow().get('month') + 1),
package/lib/esm/index.js CHANGED
@@ -90,7 +90,7 @@ import { getUserRoleMap, hasAICFOAccess, hasAdminLevelAccess, hasAnyCompanyRole,
90
90
  import { updateVendors } from './entity/vendor/vendorReducer';
91
91
  import { defaultVendorCurrency, } from './entity/vendor/vendorState';
92
92
  import { VendorExpenseTrend } from './entity/vendorExpense/vendorExpenseTrend';
93
- import initialize, { disconnectPusher, initializePusher, initializeWithNewStore, injectFeatureEpics, injectFeatureModules, updateZeniAPIClientConfig, zeniAPIClientConfig, } from './init';
93
+ import initialize, { disconnectPusher, initializePusher, initializeWithNewStore, injectFeatureEpics, injectFeatureModules, setSessionEndpointsLoader, updateZeniAPIClientConfig, updateZeniAPIEndpoints, zeniAPIClientConfig, } from './init';
94
94
  import { isAccessDeniedError, isInvalidSessionError, isSuccessResponse, } from './responsePayload';
95
95
  import { clearAll } from './rootActions';
96
96
  import { fetchAccountList } from './view/accountList/accountListReducer';
@@ -485,7 +485,7 @@ export { updateCreditAgentMacro, updateCreditAgentRow, updateCreditAgentRows, }
485
485
  export { getCreditAgentRows, getCreditAgentMacroEntity, } from './entity/creditAgent/creditAgentSelector';
486
486
  export { saveJeAccountSettings, saveJeAccountSettingsLocalData };
487
487
  export default initialize;
488
- export { initializePusher, disconnectPusher, Dayjs, dateInLocal as zeniDateInLocal, date as zeniDate, dateLocal, dateNow, getBusinessDayOfDate, formatZeniDateFY as formatZeniDate, getFYMonths, getFYQuarterAndYear, getStartOfAndEndOfTimeframeForFY, getActualPeriodOfFYQtr, getActualPeriodOfFY, getLocalTimezone, addPeriod, subtractPeriod, setLocalTimezone, updateZeniDateLocaleID, toZeniUrl, toZeniUrlWithoutBaseURL, updateZeniAPIClientConfig, zeniAPIClientConfig, injectFeatureEpics, injectFeatureModules, initializeWithNewStore, getTimeframeTickTag, isIncompleteMonthPresentInTimeframeTick, getLastMonthOfFYQuarter, getLastMonthOfFYYear, getMonthIndex, dateFromYearMonthDate, getMinDate, };
488
+ export { initializePusher, disconnectPusher, Dayjs, dateInLocal as zeniDateInLocal, date as zeniDate, dateLocal, dateNow, getBusinessDayOfDate, formatZeniDateFY as formatZeniDate, getFYMonths, getFYQuarterAndYear, getStartOfAndEndOfTimeframeForFY, getActualPeriodOfFYQtr, getActualPeriodOfFY, getLocalTimezone, addPeriod, subtractPeriod, setLocalTimezone, updateZeniDateLocaleID, toZeniUrl, toZeniUrlWithoutBaseURL, updateZeniAPIClientConfig, updateZeniAPIEndpoints, setSessionEndpointsLoader, zeniAPIClientConfig, injectFeatureEpics, injectFeatureModules, initializeWithNewStore, getTimeframeTickTag, isIncompleteMonthPresentInTimeframeTick, getLastMonthOfFYQuarter, getLastMonthOfFYYear, getMonthIndex, dateFromYearMonthDate, getMinDate, };
489
489
  export { toAmount };
490
490
  export { toReportID, toReportFormatStrict, isCashFlowOrBalanceSheetReport, isBalanceSheetReport, isBalanceSheetClassesViewReport, isBalanceSheetProjectViewReport, isCashFlowClassesViewReport, isCashFlowProjectViewReport, isCashFlowReport, isGroupedCashFlowReport, isGroupedBalanceSheetReport, isDashboardReport, isDashboardClassesViewReport, isDashboardProjectViewReport, isPAndLReport, isPAndLClassesViewReport, isPAndLProjectViewReport, isAgingReport, isOpExByVendorReport, isFluxAnalysisOpExReport, };
491
491
  export { toCOABalanceTimeframe, };
package/lib/esm/init.js CHANGED
@@ -2,6 +2,7 @@ import configureNewStore from './configureStore';
2
2
  import { ZeniAPIClient } from './zeniAPI';
3
3
  import { setZeniAPIClient, zeniAPI } from './zeniAPIClientState';
4
4
  export { zeniAPI } from './zeniAPIClientState';
5
+ export { setSessionEndpointsLoader } from './sessionEndpointsLoader';
5
6
  export { disconnectPusher, initializePusher, pusher } from './pusherClient';
6
7
  export let store;
7
8
  let initialized = false;
@@ -13,11 +14,10 @@ let initialized = false;
13
14
  */
14
15
  export default function initialize(restEndPoints, userId, sessionId, tenantId, isSandboxEnv, onSessionInvalidated) {
15
16
  if (initialized) {
16
- console.warn(`Already initialized with url ${JSON.stringify(zeniAPI.apiEndPoints)}`);
17
+ console.warn('client-epic-state is already initialized');
17
18
  return store;
18
19
  }
19
20
  initialized = true;
20
- console.info(`initializing with ${JSON.stringify(restEndPoints)}`);
21
21
  initialize3rdPartyExtensions();
22
22
  setZeniAPIClient(new ZeniAPIClient(restEndPoints, userId, sessionId, tenantId, onSessionInvalidated));
23
23
  store = configureNewStore(zeniAPI, isSandboxEnv);
@@ -35,6 +35,18 @@ export { injectFeatureModules, injectFeatureEpics } from './configureStore';
35
35
  export function updateZeniAPIClientConfig(userId, sessionId, tenantId) {
36
36
  zeniAPI.update(userId, sessionId, tenantId);
37
37
  }
38
+ /**
39
+ * Replace the REST endpoints the API client calls. Epics read the endpoints
40
+ * at request time, so every request made after this uses the new ones.
41
+ * Note: This version SHOULD BE used only in the client side.
42
+ * @param restEndPoints
43
+ */
44
+ export function updateZeniAPIEndpoints(restEndPoints) {
45
+ if (zeniAPI == null) {
46
+ throw new Error('Call initialize() before updateZeniAPIEndpoints()');
47
+ }
48
+ zeniAPI.apiEndPoints = restEndPoints;
49
+ }
38
50
  /**
39
51
  * Returns current Zeni REST API client config.
40
52
  * @returns
@@ -61,7 +73,6 @@ export function zeniAPIClientConfig() {
61
73
  * @param tenantId tenant id
62
74
  */
63
75
  export async function initializeWithNewStore(restEndPoints, userId, sessionId, tenantId) {
64
- console.info(`initializeWithNewStore with ${JSON.stringify(restEndPoints)}`);
65
76
  initialize3rdPartyExtensions();
66
77
  const zeniHttpClient = new ZeniAPIClient(restEndPoints, userId, sessionId, tenantId);
67
78
  const store = configureNewStore(zeniHttpClient, false);
@@ -0,0 +1,7 @@
1
+ let sessionEndpointsLoader;
2
+ export function setSessionEndpointsLoader(loader) {
3
+ sessionEndpointsLoader = loader;
4
+ }
5
+ export function getSessionEndpointsLoader() {
6
+ return sessionEndpointsLoader;
7
+ }
@@ -26,9 +26,10 @@ export const fetchReconciliationViewEpic = (actions$, state$, zeniAPI) => action
26
26
  }
27
27
  let fetchState;
28
28
  if (accountId != null) {
29
+ // Period bucket can be unhydrated during app-shell load.
29
30
  fetchState =
30
31
  accountReconciliationRecords[toMonthYearPeriodId(selectedPeriod)]
31
- .reconciliationByAccountID[accountId].transactionFetchState
32
+ ?.reconciliationByAccountID[accountId]?.transactionFetchState
32
33
  .fetchState;
33
34
  }
34
35
  else {
@@ -4,6 +4,10 @@ import { getClassById } from '../../../entity/class/classSelector';
4
4
  import { toProjectBasePayload, } from '../../../entity/project/projectPayload';
5
5
  import { getProjectById } from '../../../entity/project/projectSelector';
6
6
  import { getVendorByQboId, getVendorByVendorId, } from '../../../entity/vendor/vendorSelector';
7
+ const POSTING_TYPE_NAME = {
8
+ credit: 'Credit',
9
+ debit: 'Debit',
10
+ };
7
11
  const toRemitToAddressPayload = (address) => {
8
12
  if (address == null) {
9
13
  return undefined;
@@ -35,10 +39,12 @@ const toLinePayload = (state, line, transactionType) => {
35
39
  });
36
40
  }
37
41
  if (transactionType === 'journal_entry') {
38
- lineDetail.posting_type = line.postingType;
42
+ if (line.postingType != null) {
43
+ lineDetail.posting_type_name = POSTING_TYPE_NAME[line.postingType];
44
+ }
39
45
  const vendorQboId = toQboLineVendorId(state, line.vendorQboId);
40
46
  if (vendorQboId != null) {
41
- lineDetail.vendor = { qbo_id: vendorQboId };
47
+ lineDetail.vendor = { vendor_id: vendorQboId };
42
48
  }
43
49
  }
44
50
  return {
@@ -128,6 +134,10 @@ export const prepareCreateTransactionPayload = (state, localData) => {
128
134
  if (transactionType === 'journal_entry') {
129
135
  return {
130
136
  ...base,
137
+ ...(localData.documentNumber != null &&
138
+ localData.documentNumber !== '' && {
139
+ document_id: localData.documentNumber,
140
+ }),
131
141
  lines,
132
142
  };
133
143
  }
@@ -141,6 +151,8 @@ export const prepareCreateTransactionPayload = (state, localData) => {
141
151
  if (transactionType === 'check') {
142
152
  return {
143
153
  ...purchaseBase,
154
+ // The form has no payment method field for a check; qbo_purchase.py still requires it.
155
+ payment_type: 'check',
144
156
  document_number: localData.documentNumber,
145
157
  print_status: localData.printStatus,
146
158
  remit_to_address: toRemitToAddressPayload(localData.remitToAddress),
@@ -1,4 +1,5 @@
1
1
  import { createSelector } from '@reduxjs/toolkit';
2
+ import { getAccountBase } from '../../../entity/account/accountSelector';
2
3
  import { getAccountListFetchState, getNestedAccountListHierarchy, } from '../../accountList/accountListSelector';
3
4
  import { getNestedClassListHierarchy } from '../../classList/classListSelector';
4
5
  import { getResolvedTransferAccounts } from '../../createTransferEntry/createTransferEntrySelector';
@@ -22,6 +23,23 @@ export const getCreateTransactionVendorRecommendations = (state, vendorQboId) =>
22
23
  recommendations: view.recommendations,
23
24
  };
24
25
  };
26
+ /**
27
+ * QBO sub-accounts share their parent's type, so filtering the root nodes keeps whole subtrees.
28
+ *
29
+ * Memoized on its own: createTransactionsState changes on every keystroke, which re-runs the view
30
+ * projection, and the filter would otherwise hand the dropdown a new array each time.
31
+ */
32
+ const getPaymentAccountListNestedAccountHierarchy = createSelector([
33
+ (state) => getNestedAccountListHierarchy(state.accountListState, 'createTransactionPaymentAccountList'),
34
+ (state) => state.accountState,
35
+ (_state, transactionType) => transactionType,
36
+ ], (hierarchy, accountState, transactionType) => {
37
+ if (transactionType !== 'check') {
38
+ return hierarchy;
39
+ }
40
+ return hierarchy.filter((node) => getAccountBase(accountState, node.accountId[0], 'account_list')
41
+ ?.accountType === 'bank');
42
+ });
25
43
  /**
26
44
  * Memoized: app-ui reads this straight from useSelector, and the vendor list and hierarchies are
27
45
  * rebuilt on every call, so an unmemoized version re-renders the page on every store action.
@@ -30,10 +48,11 @@ export const getCreateTransactionView = createSelector([
30
48
  (state) => state.transactionDetailState.createTransactionsState,
31
49
  (state) => state.vendorState.vendorByID,
32
50
  (state) => state.accountListState,
51
+ getPaymentAccountListNestedAccountHierarchy,
33
52
  (state) => state.classListState,
34
53
  (state) => getResolvedTransferAccounts(state).transferAccountsList,
35
54
  (_state, transactionType) => transactionType,
36
- ], (createTransactionsState, vendorByID, accountListState, classListState, transferAccountsList, transactionType) => ({
55
+ ], (createTransactionsState, vendorByID, accountListState, paymentAccountListNestedAccountHierarchy, classListState, transferAccountsList, transactionType) => ({
37
56
  transactionType,
38
57
  localData: createTransactionsState.newTransactionState[transactionType],
39
58
  createStatus: createTransactionsState.createStatus,
@@ -43,7 +62,7 @@ export const getCreateTransactionView = createSelector([
43
62
  lineAccountListFetchState: getAccountListFetchState(accountListState, 'createTransactionLineAccountList'),
44
63
  paymentAccountListFetchState: getAccountListFetchState(accountListState, 'createTransactionPaymentAccountList'),
45
64
  accountListNestedAccountHierarchy: getNestedAccountListHierarchy(accountListState, 'createTransactionLineAccountList'),
46
- paymentAccountListNestedAccountHierarchy: getNestedAccountListHierarchy(accountListState, 'createTransactionPaymentAccountList'),
65
+ paymentAccountListNestedAccountHierarchy,
47
66
  classListNestedAccountHierarchy: getNestedClassListHierarchy(classListState),
48
67
  transferAccountsList: transactionType === 'transfer' ? transferAccountsList : [],
49
68
  fetchState: createTransactionsState.createStatus.fetchState,
package/lib/index.d.ts CHANGED
@@ -175,7 +175,7 @@ import { Filing1099TinType } from './entity/vendor/vendorType';
175
175
  import { VendorExpenseState, VendorSpend } from './entity/vendorExpense/vendorExpenseState';
176
176
  import { VendorExpenseTrend } from './entity/vendorExpense/vendorExpenseTrend';
177
177
  import { ExternalAPIEndpoints } from './externalAPI';
178
- import initialize, { ZeniStore, disconnectPusher, initializePusher, initializeWithNewStore, injectFeatureEpics, injectFeatureModules, updateZeniAPIClientConfig, zeniAPIClientConfig } from './init';
178
+ import initialize, { ZeniStore, disconnectPusher, initializePusher, initializeWithNewStore, injectFeatureEpics, injectFeatureModules, setSessionEndpointsLoader, updateZeniAPIClientConfig, updateZeniAPIEndpoints, zeniAPIClientConfig } from './init';
179
179
  import { ZeniAPIStatus, isAccessDeniedError, isInvalidSessionError, isSuccessResponse } from './responsePayload';
180
180
  import { clearAll } from './rootActions';
181
181
  import { RootState } from './rootStateTypes';
@@ -722,7 +722,7 @@ export type { CreditAgentFocusFilter, CreditAgentSortDir, CreditAgentSortKey, Cr
722
722
  export { AccountSettingsLocalData };
723
723
  export { saveJeAccountSettings, saveJeAccountSettingsLocalData };
724
724
  export default initialize;
725
- export { initializePusher, disconnectPusher, Dayjs, ZeniDate, dateInLocal as zeniDateInLocal, date as zeniDate, dateLocal, dateNow, getBusinessDayOfDate, formatZeniDateFY as formatZeniDate, getFYMonths, getFYQuarterAndYear, getStartOfAndEndOfTimeframeForFY, getActualPeriodOfFYQtr, getActualPeriodOfFY, getLocalTimezone, addPeriod, subtractPeriod, setLocalTimezone, updateZeniDateLocaleID, ZeniUrl, toZeniUrl, toZeniUrlWithoutBaseURL, RESTAPIEndpoints, RootState, updateZeniAPIClientConfig, zeniAPIClientConfig, injectFeatureEpics, injectFeatureModules, initializeWithNewStore, ZeniStore, ZeniAPIStatus, getTimeframeTickTag, TimeFrameTickTag, isIncompleteMonthPresentInTimeframeTick, getLastMonthOfFYQuarter, getLastMonthOfFYYear, getMonthIndex, dateFromYearMonthDate, getMinDate, ExternalAPIEndpoints, };
725
+ export { initializePusher, disconnectPusher, Dayjs, ZeniDate, dateInLocal as zeniDateInLocal, date as zeniDate, dateLocal, dateNow, getBusinessDayOfDate, formatZeniDateFY as formatZeniDate, getFYMonths, getFYQuarterAndYear, getStartOfAndEndOfTimeframeForFY, getActualPeriodOfFYQtr, getActualPeriodOfFY, getLocalTimezone, addPeriod, subtractPeriod, setLocalTimezone, updateZeniDateLocaleID, ZeniUrl, toZeniUrl, toZeniUrlWithoutBaseURL, RESTAPIEndpoints, RootState, updateZeniAPIClientConfig, updateZeniAPIEndpoints, setSessionEndpointsLoader, zeniAPIClientConfig, injectFeatureEpics, injectFeatureModules, initializeWithNewStore, ZeniStore, ZeniAPIStatus, getTimeframeTickTag, TimeFrameTickTag, isIncompleteMonthPresentInTimeframeTick, getLastMonthOfFYQuarter, getLastMonthOfFYYear, getMonthIndex, dateFromYearMonthDate, getMinDate, ExternalAPIEndpoints, };
726
726
  export { ID, FetchState, FetchStateAndError, FetchedState, UpdateType, Mode, AccountViewMode, CompletionStatusType, };
727
727
  export { Amount, toAmount, Currency };
728
728
  export { View, SelectorView, Report, ReportID, toReportID, ReportIDPlusForecastID, SelectorReport, ReportFormat, toReportFormatStrict, isCashFlowOrBalanceSheetReport, isBalanceSheetReport, isBalanceSheetClassesViewReport, isBalanceSheetProjectViewReport, isCashFlowClassesViewReport, isCashFlowProjectViewReport, isCashFlowReport, isGroupedCashFlowReport, isGroupedBalanceSheetReport, isDashboardReport, isDashboardClassesViewReport, isDashboardProjectViewReport, isPAndLReport, isPAndLClassesViewReport, isPAndLProjectViewReport, isAgingReport, isOpExByVendorReport, isFluxAnalysisOpExReport, PageToken, };
@@ -1270,6 +1270,7 @@ export { getActualMatchingAmount, getActualMatchingReversalDate, getActualMatchi
1270
1270
  export type { ExpenseAutomationActualMatchingMatchView } from './view/expenseAutomationView/selectors/actualMatchingViewSelector';
1271
1271
  export type { ActualMatchingMatch, ActualMatchingMatchKind, } from './entity/actualMatching/actualMatchingState';
1272
1272
  export type { ActualMatchingMatchId } from './entity/actualMatching/actualMatchingTypes';
1273
+ export type { SessionEndpointsLoader } from './sessionEndpointsLoader';
1273
1274
  export type { DisplayCurrencyFallback } from './entity/actualMatching/actualMatchingPayload';
1274
1275
  export { fetchCustomerSummaryDetail, fetchCustomerSummaryList, resetCustomerSummaryDetailUiState, saveCustomerSummaryDetail, updateCustomerAllTransactionsTabData, updateCustomerDetailSelectedTab, updateCustomerSummaryRevenueSelection, updateCustomerSummaryScrollYOffset, updateCustomerSummarySortUiState, updateCustomerTrendFilter, } from './view/customerSummaryView/customerSummaryViewReducer';
1275
1276
  export { getCustomerSummaryAllTransactionsTabData, getCustomerSummaryDetail, getCustomerSummaryList, getCustomerSummarySelectedTabType, getCustomerSummaryTrendFilter, isCustomersTabVisible, } from './view/customerSummaryView/customerSummaryViewSelector';