@zeniai/client-epic-state 5.1.8-betaRD2 → 5.1.8-betaRR0

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 (30) hide show
  1. package/lib/entity/company/cardsVisibilityHelpers.d.ts +4 -0
  2. package/lib/entity/company/cardsVisibilityHelpers.js +14 -0
  3. package/lib/entity/tenant/tenantSelector.d.ts +1 -1
  4. package/lib/entity/tenant/tenantSelector.js +9 -11
  5. package/lib/entity/transaction/payloadTypes/transactionPayload.js +10 -0
  6. package/lib/esm/entity/company/cardsVisibilityHelpers.js +9 -0
  7. package/lib/esm/entity/tenant/tenantSelector.js +7 -9
  8. package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +10 -0
  9. package/lib/esm/index.js +2 -1
  10. package/lib/esm/view/dashboard/dashboardSelector.js +8 -43
  11. package/lib/esm/view/people/initializeEditPersonEpic.js +5 -1
  12. package/lib/esm/view/people/invitePeopleEpic.js +6 -3
  13. package/lib/esm/view/people/peopleSaveUpdatesEpic.js +7 -3
  14. package/lib/esm/view/settingsView/settingsViewHelpers.js +16 -10
  15. package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +1 -0
  16. package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +6 -0
  17. package/lib/esm/view/transactionDetail/transactionDetailLocalDataHelper.js +7 -1
  18. package/lib/index.d.ts +2 -1
  19. package/lib/index.js +30 -27
  20. package/lib/view/dashboard/dashboardSelector.js +8 -43
  21. package/lib/view/people/initializeEditPersonEpic.js +5 -1
  22. package/lib/view/people/invitePeopleEpic.js +6 -3
  23. package/lib/view/people/peopleSaveUpdatesEpic.js +7 -3
  24. package/lib/view/settingsView/settingsViewHelpers.js +15 -9
  25. package/lib/view/transactionDetail/epics/saveTransactionHelper.js +1 -0
  26. package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +6 -0
  27. package/lib/view/transactionDetail/transactionDetailLocalDataHelper.js +7 -1
  28. package/lib/view/transactionDetail/transactionDetailState.d.ts +1 -0
  29. package/lib/view/transactionDetail/transactionDetailTypes.d.ts +1 -0
  30. package/package.json +1 -1
@@ -0,0 +1,4 @@
1
+ import { UserRoleType } from '../userRole/userRoleType';
2
+ import { Company } from './companyStateTypes';
3
+ export declare const isCardsProductEnabledOnCompany: (company: Company | undefined) => boolean;
4
+ export declare const filterChargeCardRolesWhenProductDisabled: (roles: UserRoleType[], company: Company | undefined) => UserRoleType[];
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.filterChargeCardRolesWhenProductDisabled = exports.isCardsProductEnabledOnCompany = void 0;
4
+ const isCardsProductEnabledOnCompany = (company) => Boolean(company?.companyChargeCardInfo?.isChargeCardEnabled) ||
5
+ Boolean(company?.companyDebitCardInfo?.isDebitCardEnabled);
6
+ exports.isCardsProductEnabledOnCompany = isCardsProductEnabledOnCompany;
7
+ const CHARGE_CARD_USER_ROLES = [
8
+ 'charge_card_admin',
9
+ 'charge_card_user',
10
+ ];
11
+ const filterChargeCardRolesWhenProductDisabled = (roles, company) => (0, exports.isCardsProductEnabledOnCompany)(company)
12
+ ? roles
13
+ : roles.filter((role) => !CHARGE_CARD_USER_ROLES.includes(role));
14
+ exports.filterChargeCardRolesWhenProductDisabled = filterChargeCardRolesWhenProductDisabled;
@@ -85,7 +85,7 @@ export declare const getCurrentTenantExternalConnections: (tenantState: TenantSt
85
85
  export declare const toTenantCoreDetailsView: (tenantsBaseView: TenantBaseView[]) => TenantCoreDetailsView[];
86
86
  export declare const isTenantBankingOnly: (isDebitCardFlagEnabled: boolean, tenant: Tenant | undefined) => boolean;
87
87
  export declare const isTenantCardsOnly: (tenant: Tenant | undefined) => boolean;
88
- export declare const isTenantUsingAccountingServices: (tenant: Tenant | undefined) => boolean;
88
+ export declare const isTenantAccountingServicesEnabled: (tenant: Tenant | undefined) => boolean;
89
89
  export declare const getIsAccountingClassesEnabled: (state: RootState) => boolean;
90
90
  export declare const getIsAccountingProjectsEnabled: (state: RootState) => boolean;
91
91
  export declare const isTenantBookkeepingEnabled: (tenant: Tenant | undefined) => boolean;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.isTenantTreasuryEnabled = exports.isOtherProductsEnabledForTenant = exports.isTenantBookkeepingEnabled = exports.getIsAccountingProjectsEnabled = exports.getIsAccountingClassesEnabled = exports.isTenantUsingAccountingServices = exports.isTenantCardsOnly = exports.isTenantBankingOnly = exports.toTenantCoreDetailsView = exports.getCurrentTenantExternalConnections = exports.isTenantUsingZeniCOA = exports.isZeniDomainTenant = exports.getTenantBaseViewForTenantView = exports.getTenantsCoreDetailsByCheckInDateSelector = exports.getTenantsBaseByCheckInDateSelector = exports.getTenantBaseById = exports.getTenantsByCheckInDateSelector = exports.getCurrentTenant = exports.getTenantBaseViewForTenantId = void 0;
6
+ exports.isTenantTreasuryEnabled = exports.isOtherProductsEnabledForTenant = exports.isTenantBookkeepingEnabled = exports.getIsAccountingProjectsEnabled = exports.getIsAccountingClassesEnabled = exports.isTenantAccountingServicesEnabled = exports.isTenantCardsOnly = exports.isTenantBankingOnly = exports.toTenantCoreDetailsView = exports.getCurrentTenantExternalConnections = exports.isTenantUsingZeniCOA = exports.isZeniDomainTenant = exports.getTenantBaseViewForTenantView = exports.getTenantsCoreDetailsByCheckInDateSelector = exports.getTenantsBaseByCheckInDateSelector = exports.getTenantBaseById = exports.getTenantsByCheckInDateSelector = exports.getCurrentTenant = exports.getTenantBaseViewForTenantId = void 0;
7
7
  exports.getTenant = getTenant;
8
8
  exports.getOnboardingTenantByTenantId = getOnboardingTenantByTenantId;
9
9
  const toolkit_1 = require("@reduxjs/toolkit");
@@ -280,17 +280,15 @@ const isTenantCardsOnly = (tenant) => {
280
280
  : false;
281
281
  };
282
282
  exports.isTenantCardsOnly = isTenantCardsOnly;
283
- const isTenantUsingAccountingServices = (tenant) => {
284
- const settings = tenant?.productSettings;
285
- if (settings == null) {
286
- return false;
287
- }
288
- return (settings.isCfoEnabled === true ||
289
- settings.isTaxEnabled === true ||
290
- settings.isPayrollEnabled === true ||
291
- settings.isBookkeepingEnabled === true);
283
+ const isTenantAccountingServicesEnabled = (tenant) => {
284
+ return tenant != null && tenant.productSettings != null
285
+ ? tenant.productSettings.isCfoEnabled === true ||
286
+ tenant.productSettings.isTaxEnabled === true ||
287
+ tenant.productSettings.isPayrollEnabled === true ||
288
+ tenant.productSettings.isBookkeepingEnabled === true
289
+ : false;
292
290
  };
293
- exports.isTenantUsingAccountingServices = isTenantUsingAccountingServices;
291
+ exports.isTenantAccountingServicesEnabled = isTenantAccountingServicesEnabled;
294
292
  const getIsAccountingClassesEnabled = (state) => {
295
293
  const { currentTenantId, tenantsById } = state.tenantState;
296
294
  if (currentTenantId == null) {
@@ -157,6 +157,16 @@ const toTransactionPayload = (transaction) => {
157
157
  lines: transaction?.lines?.map((line) => (0, transactionLinePayload_1.toLinePayload)(line)) ?? [],
158
158
  recommendations: toRecommendationsPayload(transaction.lines ?? [], transaction.recommendations ?? {}),
159
159
  };
160
+ // Only carry `document_id` (the journal-entry title / document number) when
161
+ // the transaction actually has one, so transaction types that never expose
162
+ // the title don't start sending the key, and we never emit an empty string
163
+ // that the server could interpret as clearing the number.
164
+ if (transaction.documentId != null) {
165
+ transactionPayload = {
166
+ ...transactionPayload,
167
+ document_id: transaction.documentId,
168
+ };
169
+ }
160
170
  //note: for transaction type deposit and refund account is must for put call
161
171
  if (transaction.account != null &&
162
172
  (transaction.type === 'deposit' || transaction.type === 'refund')) {
@@ -0,0 +1,9 @@
1
+ export const isCardsProductEnabledOnCompany = (company) => Boolean(company?.companyChargeCardInfo?.isChargeCardEnabled) ||
2
+ Boolean(company?.companyDebitCardInfo?.isDebitCardEnabled);
3
+ const CHARGE_CARD_USER_ROLES = [
4
+ 'charge_card_admin',
5
+ 'charge_card_user',
6
+ ];
7
+ export const filterChargeCardRolesWhenProductDisabled = (roles, company) => isCardsProductEnabledOnCompany(company)
8
+ ? roles
9
+ : roles.filter((role) => !CHARGE_CARD_USER_ROLES.includes(role));
@@ -265,15 +265,13 @@ export const isTenantCardsOnly = (tenant) => {
265
265
  tenant.productSettings.isSpendManagementEnabled === false
266
266
  : false;
267
267
  };
268
- export const isTenantUsingAccountingServices = (tenant) => {
269
- const settings = tenant?.productSettings;
270
- if (settings == null) {
271
- return false;
272
- }
273
- return (settings.isCfoEnabled === true ||
274
- settings.isTaxEnabled === true ||
275
- settings.isPayrollEnabled === true ||
276
- settings.isBookkeepingEnabled === true);
268
+ export const isTenantAccountingServicesEnabled = (tenant) => {
269
+ return tenant != null && tenant.productSettings != null
270
+ ? tenant.productSettings.isCfoEnabled === true ||
271
+ tenant.productSettings.isTaxEnabled === true ||
272
+ tenant.productSettings.isPayrollEnabled === true ||
273
+ tenant.productSettings.isBookkeepingEnabled === true
274
+ : false;
277
275
  };
278
276
  export const getIsAccountingClassesEnabled = (state) => {
279
277
  const { currentTenantId, tenantsById } = state.tenantState;
@@ -152,6 +152,16 @@ export const toTransactionPayload = (transaction) => {
152
152
  lines: transaction?.lines?.map((line) => toLinePayload(line)) ?? [],
153
153
  recommendations: toRecommendationsPayload(transaction.lines ?? [], transaction.recommendations ?? {}),
154
154
  };
155
+ // Only carry `document_id` (the journal-entry title / document number) when
156
+ // the transaction actually has one, so transaction types that never expose
157
+ // the title don't start sending the key, and we never emit an empty string
158
+ // that the server could interpret as clearing the number.
159
+ if (transaction.documentId != null) {
160
+ transactionPayload = {
161
+ ...transactionPayload,
162
+ document_id: transaction.documentId,
163
+ };
164
+ }
155
165
  //note: for transaction type deposit and refund account is must for put call
156
166
  if (transaction.account != null &&
157
167
  (transaction.type === 'deposit' || transaction.type === 'refund')) {
package/lib/esm/index.js CHANGED
@@ -43,6 +43,7 @@ import { getChargeCardById } from './entity/chargeCard/chargeCardSelector';
43
43
  import { attachmentFilePathToAttachment, } from './entity/chargeCardTransaction/chargeCardTransactionPayload';
44
44
  import { updateChargeCardTransactionAttachments } from './entity/chargeCardTransaction/chargeCardTransactionReducer';
45
45
  import { updateChargeCardTransactionFromPusher, updateChargeCardTransactionReceiptFromPusher, updateChargeCardTransactionStatusFromPusher, } from './entity/chargeCardTransaction/chargeCardTransactionReducer';
46
+ import { filterChargeCardRolesWhenProductDisabled, isCardsProductEnabledOnCompany, } from './entity/company/cardsVisibilityHelpers';
46
47
  import { getControllersName, getFirstControllerEmail, getFirstControllerId, } from './entity/company/companyHelper';
47
48
  import { getCompanyByCompanyId, getCompanyInfoForAllCockpitCompaniesInState, getControllersForCompany, } from './entity/company/companySelector';
48
49
  import { ALL_ACCOUNTING_CONNECTION_CREATION_MODES, isCompanyEligibleForTreasury, } from './entity/company/companyStateTypes';
@@ -536,7 +537,7 @@ export { getEntityAutoCompleteResults };
536
537
  export { updateEntities, clearAllEntities };
537
538
  export { getEntityByEntityIDs };
538
539
  export { getAddressByAddressId };
539
- export { ALL_ACCOUNTING_CONNECTION_CREATION_MODES, isCompanyEligibleForTreasury, };
540
+ export { ALL_ACCOUNTING_CONNECTION_CREATION_MODES, isCompanyEligibleForTreasury, isCardsProductEnabledOnCompany, filterChargeCardRolesWhenProductDisabled, };
540
541
  export { getCompanyByCompanyId, getControllersForCompany, getCompanyInfoForAllCockpitCompaniesInState, getFirstControllerEmail, getFirstControllerId, getControllersName, };
541
542
  export { getCompanyManagementView, getPlanListZeniSku, getAddonListZeniSku, };
542
543
  export { getParentSubsidiaryManagementView };
@@ -57,20 +57,13 @@ export const getDashboard = createSelector(tenantSelector, getCardBalance, getCa
57
57
  const hasTasksCardAccess = tenants.currentTenant?.excludedResources?.resources?.find((resource) => resource.resource === '/reports/task_card') == null;
58
58
  let cardsCopy = [...cards];
59
59
  const cardsToRemove = new Set();
60
- const chargeCardInfo = tenants.currentTenant.companyChargeCardInfo?.info;
61
- const creditAccountLimit = chargeCardInfo?.chargeCardsCreditAccountLimit ?? 0;
62
- let isZeniPromoCardOn4thPosition = true;
63
- const isChargeCardEnabled = chargeCardInfo?.isChargeCardEnabled ?? false;
60
+ // Credit-only express-interest promo; always omitted while cards are company-product-gated. Reintroduce only with an explicit show rule.
61
+ cardsToRemove.add('zeni_promo_card');
64
62
  if (cardBalance != null &&
65
63
  cardBalance.fetchState === 'Completed' &&
66
64
  (cardBalance.accountsInOrder.length === 0 ||
67
65
  cardBalance.status?.code !== 200)) {
68
66
  cardsToRemove.add('card_balance');
69
- isZeniPromoCardOn4thPosition = false;
70
- }
71
- if (isChargeCardEnabled || creditAccountLimit === -1) {
72
- cardsToRemove.add('zeni_promo_card');
73
- isZeniPromoCardOn4thPosition = false;
74
67
  }
75
68
  if (hasTopExAccess === false) {
76
69
  cardsToRemove.add('top_expenses');
@@ -160,57 +153,29 @@ export const getDashboard = createSelector(tenantSelector, getCardBalance, getCa
160
153
  cardsToRemove.add('bill_pay_card');
161
154
  cardsToRemove.add('reimbursement_card');
162
155
  }
163
- // //show cards carousel as priority, if ZC promo is coming in 2nd position, follow show promos based on Checking promo > Bills & Reimbursement promo
164
- // //else if ZC promo is coming in 3rd position, follow ZC promo > Checking promo > Bills & Reimbursement promo
165
- if (isZeniPromoCardOn4thPosition) {
156
+ const showZeniAccountsPromoCard = zeniAccountsPromoCard.isShowDepositAccountsPromo === true;
157
+ if (showZeniAccountsPromoCard) {
166
158
  cardsToRemove.add('bill_pay_promo_card');
167
159
  cardsToRemove.add('reimbursement_promo_card');
168
- cardsToRemove.add('zeni_accounts_promo_card');
169
160
  }
170
161
  else {
171
- const showZeniAccountsPromoCard = zeniAccountsPromoCard.isShowDepositAccountsPromo === true;
172
- if (showZeniAccountsPromoCard) {
173
- cardsToRemove.add('bill_pay_promo_card');
174
- cardsToRemove.add('reimbursement_promo_card');
175
- }
176
- else {
177
- cardsToRemove.add('zeni_accounts_promo_card');
178
- }
162
+ cardsToRemove.add('zeni_accounts_promo_card');
179
163
  }
180
164
  // remove treasury promo card if its already enabled
181
165
  const isTreasuryTOSAccepted = tenants.currentTenant.companyTreasuryInfo?.info?.isTreasuryTOSAccepted;
182
166
  if (isTreasuryTOSAccepted === true || isTreasuryFeatureEnabled === false) {
183
167
  cardsToRemove.add('treasury_promo_card');
184
168
  }
185
- // More than one promo card can't be shown in the dashboard(Priority: Treasury>Cards>Accounts>Bill> Remi)
186
- // There is an exception when number of card accounts connected to QBO is zero, in that case we replace card_balance tile in 2nd position with zeni_promo_card,
187
- // so 3rd position tile could be any other promo card based on priority order.
169
+ // More than one promo card can't be shown on the dashboard (priority: Treasury > Accounts > Bill > Remi).
188
170
  const PROMO_CARD_PRIORITY_ORDER = [
189
171
  'treasury_promo_card',
190
- 'zeni_promo_card',
191
172
  'zeni_accounts_promo_card',
192
173
  'bill_pay_promo_card',
193
174
  'reimbursement_promo_card',
194
175
  ];
195
- const promoCards = PROMO_CARD_PRIORITY_ORDER;
196
- const promoCardsTobeRetained = promoCards.filter((c) => !cardsToRemove.has(c));
176
+ const promoCardsTobeRetained = PROMO_CARD_PRIORITY_ORDER.filter((c) => !cardsToRemove.has(c));
197
177
  if (promoCardsTobeRetained.length > 1) {
198
- const cardsToKeep = new Set();
199
- if (cardsToRemove.has('card_balance') &&
200
- promoCardsTobeRetained.includes('zeni_promo_card')) {
201
- // zeni_promo_card is the primary promo card when card_balance is removed
202
- cardsToKeep.add('zeni_promo_card');
203
- // Also keep the highest priority non-zeni promo card as the 2nd
204
- const secondCard = promoCardsTobeRetained.find((card) => card !== 'zeni_promo_card');
205
- if (secondCard != null) {
206
- cardsToKeep.add(secondCard);
207
- }
208
- }
209
- else {
210
- // Keep only the highest priority promo card
211
- cardsToKeep.add(promoCardsTobeRetained[0]);
212
- }
213
- // Remove all other promo cards not in cardsToKeep
178
+ const cardsToKeep = new Set([promoCardsTobeRetained[0]]);
214
179
  promoCardsTobeRetained.forEach((card) => {
215
180
  if (!cardsToKeep.has(card)) {
216
181
  cardsToRemove.add(card);
@@ -1,5 +1,7 @@
1
1
  import { from } from 'rxjs';
2
2
  import { filter, mergeMap } from 'rxjs/operators';
3
+ import { filterChargeCardRolesWhenProductDisabled } from '../../entity/company/cardsVisibilityHelpers';
4
+ import { getCurrentTenant } from '../../entity/tenant/tenantSelector';
3
5
  import { getUserByUserId } from '../../entity/user/userSelector';
4
6
  import { getUserRoleByUserId } from '../../entity/userRole/userRoleSelector';
5
7
  import { initializeEditPerson, peopleSaveDataInLocalStore, } from './peopleReducer';
@@ -18,11 +20,13 @@ export const initializeEditPersonEpic = (actions$, state$) => actions$.pipe(filt
18
20
  };
19
21
  const email = person.user?.email;
20
22
  const { userRoles, managerUserId: managerId, accountingClassIDs, } = person.userRole;
23
+ const currentTenant = getCurrentTenant(state$.value);
24
+ const rolesForLocalStore = filterChargeCardRolesWhenProductDisabled(userRoles, currentTenant.company);
21
25
  fetchActions.push(peopleSaveDataInLocalStore({
22
26
  peopleLocalData: [
23
27
  {
24
28
  email: email != null ? [email] : [],
25
- role: userRoles,
29
+ role: rolesForLocalStore,
26
30
  managerId,
27
31
  departmentId: accountingClassIDs[0],
28
32
  },
@@ -1,6 +1,8 @@
1
1
  import { of } from 'rxjs';
2
2
  import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { filterChargeCardRolesWhenProductDisabled } from '../../entity/company/cardsVisibilityHelpers';
3
4
  import { openSnackbar } from '../../entity/snackbar/snackbarReducer';
5
+ import { getCurrentTenant } from '../../entity/tenant/tenantSelector';
4
6
  import { updateAllUsers } from '../../entity/user/userReducer';
5
7
  import { updateUserRoles } from '../../entity/userRole/userRoleReducer';
6
8
  import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
@@ -8,7 +10,8 @@ import { updateManagersListOnRoleChange, } from './helpers/updateManagersListOnR
8
10
  import { invitePeople, invitePeopleFailure, invitePeopleSuccess, } from './peopleReducer';
9
11
  export const invitePeopleEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(invitePeople.match), switchMap(() => {
10
12
  const peopleLocalData = state$.value.peopleState.personDetails.localData;
11
- const invitePayload = toInvitePayloadFromLocalData(peopleLocalData);
13
+ const currentTenant = getCurrentTenant(state$.value);
14
+ const invitePayload = toInvitePayloadFromLocalData(peopleLocalData, currentTenant.company);
12
15
  return zeniAPI
13
16
  .postAndGetJSON(`${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/invites`, invitePayload)
14
17
  .pipe(mergeMap((response) => {
@@ -31,11 +34,11 @@ export const invitePeopleEpic = (actions$, state$, zeniAPI) => actions$.pipe(fil
31
34
  }
32
35
  }), catchError((error) => of(invitePeopleFailure(createZeniAPIStatus('Unexpected error', 'User Roles REST API call errored out' + JSON.stringify(error))))));
33
36
  }));
34
- const toInvitePayloadFromLocalData = (peopleLocalData) => {
37
+ const toInvitePayloadFromLocalData = (peopleLocalData, company) => {
35
38
  const invitedPeople = peopleLocalData
36
39
  .map((local) => {
37
40
  const rolesPayload = {};
38
- local.role.forEach((role) => {
41
+ filterChargeCardRolesWhenProductDisabled(local.role, company).forEach((role) => {
39
42
  rolesPayload[`is_${role}`] = true;
40
43
  });
41
44
  return local.email.map((mail) => {
@@ -1,6 +1,8 @@
1
1
  import { from, of } from 'rxjs';
2
2
  import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { filterChargeCardRolesWhenProductDisabled } from '../../entity/company/cardsVisibilityHelpers';
3
4
  import { openSnackbar } from '../../entity/snackbar/snackbarReducer';
5
+ import { getCurrentTenant } from '../../entity/tenant/tenantSelector';
4
6
  import { updateUserRoles } from '../../entity/userRole/userRoleReducer';
5
7
  import { hasZeniRoleOrCompanyOfficerAccess } from '../../entity/userRole/userRoleType';
6
8
  import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
@@ -10,7 +12,8 @@ export const peopleSaveUpdatesEpic = (actions$, state$, zeniAPI) => actions$.pip
10
12
  const { localData, person } = state$.value.peopleState.personDetails;
11
13
  const { userRole } = person;
12
14
  const { isZeniTenant } = action.payload;
13
- const updatesPayload = toPersonUpdatableInfoPayload(localData[0], isZeniTenant, person);
15
+ const currentTenant = getCurrentTenant(state$.value);
16
+ const updatesPayload = toPersonUpdatableInfoPayload(localData[0], isZeniTenant, person, currentTenant.company);
14
17
  return zeniAPI
15
18
  .putAndGetJSON(`${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/user-roles/${userRole.userRoleId}`, updatesPayload)
16
19
  .pipe(mergeMap((response) => {
@@ -37,7 +40,7 @@ export const peopleSaveUpdatesEpic = (actions$, state$, zeniAPI) => actions$.pip
37
40
  }
38
41
  }), catchError((error) => of(peopleSaveUpdatesFailure(createZeniAPIStatus('Unexpected error', 'User Roles save updates errored out' + JSON.stringify(error))))));
39
42
  }));
40
- const toPersonUpdatableInfoPayload = (info, isZeniTenant, person) => {
43
+ const toPersonUpdatableInfoPayload = (info, isZeniTenant, person, company) => {
41
44
  const payload = {};
42
45
  const { accountingClassIDs, managerUserId, userRoles } = person.userRole;
43
46
  if (info.departmentId != null &&
@@ -52,6 +55,7 @@ const toPersonUpdatableInfoPayload = (info, isZeniTenant, person) => {
52
55
  info.managerId !== 'no_manager' ? info.managerId : null;
53
56
  }
54
57
  if (info.role != null) {
58
+ const rolesForUpdate = filterChargeCardRolesWhenProductDisabled(info.role, company);
55
59
  /**
56
60
  * Mark previously selected roles as false and new roles true
57
61
  */
@@ -62,7 +66,7 @@ const toPersonUpdatableInfoPayload = (info, isZeniTenant, person) => {
62
66
  }
63
67
  rolesPayload[`is_${role}`] = false;
64
68
  });
65
- info.role.forEach((role) => {
69
+ rolesForUpdate.forEach((role) => {
66
70
  rolesPayload[`is_${role}`] = true;
67
71
  });
68
72
  Object.assign(payload, rolesPayload);
@@ -1,4 +1,5 @@
1
- import { isTenantBankingOnly, isTenantCardsOnly, isTenantUsingAccountingServices, } from '../../entity/tenant/tenantSelector';
1
+ import { isCardsProductEnabledOnCompany } from '../../entity/company/cardsVisibilityHelpers';
2
+ import { isTenantAccountingServicesEnabled, isTenantBankingOnly, isTenantCardsOnly, } from '../../entity/tenant/tenantSelector';
2
3
  import { hasAnyAdminLevelAccess, hasBillPayAccessible, hasBookKeepingAdminLevelAccess, hasBookKeepingUserLevelAccess, hasChargeCardAccessible, hasFullOrAdminLevelAccess, hasInvestorBankerLevelAccess, hasReimbursementAccess, hasReimbursementAccessible, hasSuperAdminLevelAccess, hasZeniAccountsAccessible, isZeniSignedInUser, } from '../../entity/userRole/userRoleType';
3
4
  import { isVendorsTabVisible } from '../vendorList/vendorListSelector';
4
5
  export const isAccountingTabVisible = (userRole, isDebitCardFlagEnabled, currentTenant, userRoleMap) => {
@@ -10,8 +11,9 @@ export const isAccountingTabVisible = (userRole, isDebitCardFlagEnabled, current
10
11
  hasBillPayAccessible(currentTenant, userRoleMap) ||
11
12
  hasReimbursementAccessible(currentTenant, userRoleMap) ||
12
13
  hasFullOrAdminLevelAccess(userRole)) &&
13
- isTenantBankingOnly(isDebitCardFlagEnabled, currentTenant) === false &&
14
- isTenantCardsOnly(currentTenant) === false);
14
+ (isTenantAccountingServicesEnabled(currentTenant) ||
15
+ (isTenantBankingOnly(isDebitCardFlagEnabled, currentTenant) === false &&
16
+ isTenantCardsOnly(currentTenant) === false)));
15
17
  }
16
18
  else {
17
19
  return false;
@@ -29,8 +31,9 @@ export const isApprovalRulesTabVisible = (userRole, isDebitCardFlagEnabled, curr
29
31
  hasReimbursementAccessible(currentTenant, userRoleMap) ||
30
32
  ((isBillPayTOSAccepted || isReimbursementTOSAccepted) &&
31
33
  hasFullOrAdminLevelAccess(userRole))) &&
32
- isTenantBankingOnly(isDebitCardFlagEnabled, currentTenant) === false &&
33
- isTenantCardsOnly(currentTenant) === false);
34
+ (isTenantAccountingServicesEnabled(currentTenant) ||
35
+ (isTenantBankingOnly(isDebitCardFlagEnabled, currentTenant) === false &&
36
+ isTenantCardsOnly(currentTenant) === false)));
34
37
  }
35
38
  else {
36
39
  return false;
@@ -55,7 +58,8 @@ export const isBankConnectionsTabVisible = (currentTenant, userRoleMap) => {
55
58
  return (hasBillPayAccessible(currentTenant, userRoleMap) ||
56
59
  hasReimbursementAccessible(currentTenant, userRoleMap) ||
57
60
  hasZeniAccountsAccessible(currentTenant, userRoleMap) ||
58
- hasChargeCardAccessible(currentTenant, userRoleMap));
61
+ (hasChargeCardAccessible(currentTenant, userRoleMap) &&
62
+ isCardsProductEnabledOnCompany(currentTenant.company)));
59
63
  }
60
64
  else {
61
65
  return false;
@@ -69,7 +73,8 @@ export const isBusinessVerificationTabVisible = (currentTenant, userRoleMap) =>
69
73
  return (hasBillPayAccessible(currentTenant, userRoleMap) ||
70
74
  hasReimbursementAccessible(currentTenant, userRoleMap) ||
71
75
  hasZeniAccountsAccessible(currentTenant, userRoleMap) ||
72
- hasChargeCardAccessible(currentTenant, userRoleMap));
76
+ (hasChargeCardAccessible(currentTenant, userRoleMap) &&
77
+ isCardsProductEnabledOnCompany(currentTenant.company)));
73
78
  }
74
79
  else {
75
80
  return false;
@@ -94,7 +99,7 @@ export const isIntegrationsTabVisible = (userRole, isDebitCardFlagEnabled, curre
94
99
  }
95
100
  if (isSettingsVisible(currentTenant)) {
96
101
  return (hasFullOrAdminLevelAccess(userRole) &&
97
- (isTenantUsingAccountingServices(currentTenant) ||
102
+ (isTenantAccountingServicesEnabled(currentTenant) ||
98
103
  !(isTenantBankingOnly(isDebitCardFlagEnabled, currentTenant) ||
99
104
  isTenantCardsOnly(currentTenant))));
100
105
  }
@@ -147,6 +152,7 @@ export const isNotificationsTabVisible = (notificationSettings, signedInUseEmail
147
152
  const { reminderNotificationSettings, monthEndInsightsNotificationSettings } = notificationSettings;
148
153
  return ((isRemindersSectionVisibleOnSettingsPage(reminderNotificationSettings) ||
149
154
  isMonthEndNotificationsSectionVisibleOnSettingsPage(monthEndInsightsNotificationSettings, signedInUseEmail)) &&
150
- isTenantBankingOnly(isDebitCardFlagEnabled, currentTenant) === false &&
151
- isTenantCardsOnly(currentTenant) === false);
155
+ (isTenantAccountingServicesEnabled(currentTenant) ||
156
+ (isTenantBankingOnly(isDebitCardFlagEnabled, currentTenant) === false &&
157
+ isTenantCardsOnly(currentTenant) === false)));
152
158
  };
@@ -29,6 +29,7 @@ export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDe
29
29
  const entityUpdates = {};
30
30
  const isTransactionMisCategorized = isTransactionMiscategorized(transaction, isExpenseAutomationEnabled);
31
31
  updates.memo = transactionDetailLocalData.memo;
32
+ updates.documentId = transactionDetailLocalData.documentId;
32
33
  const selectedEntity = transactionDetailLocalData.selectedEntity;
33
34
  const updatedEntityId = transactionDetailLocalData.updatePreviousTransactionsWithUpdatedVendor ===
34
35
  true
@@ -168,6 +168,12 @@ function preparePayload(transactionState, vendorState, transactionDetailState, t
168
168
  const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, vendorUpdates, customerUpdates, tranSelectedEntity) => {
169
169
  const transaction = Object.assign({}, detail);
170
170
  transaction.memo = updates.memo ?? '';
171
+ // Unlike `memo` (always reset to '' when absent), `documentId` falls back to
172
+ // the existing value rather than ''. Only the journal-entry title is
173
+ // user-editable; for every other transaction type `updates.documentId` is
174
+ // either the unchanged current value or undefined, and we must not send an
175
+ // empty `document_id` that the server would treat as clearing the number.
176
+ transaction.documentId = updates.documentId ?? transaction.documentId;
171
177
  const recommendationUpdates = {};
172
178
  for (const key in updates.updatesByLineId) {
173
179
  const lineUpdates = updates.updatesByLineId[key];
@@ -11,6 +11,7 @@ export const toTransactionDetailLocalData = (transaction, defaultVendorId, uncat
11
11
  ?.id;
12
12
  const vendorId = defaultVendorId ?? transaction.vendor?.id;
13
13
  transactionLocal.memo = transaction.memo;
14
+ transactionLocal.documentId = transaction.documentId;
14
15
  transactionLocal.vendorUpdates =
15
16
  isVendorTransaction(transaction) && vendorId != null
16
17
  ? {
@@ -421,6 +422,7 @@ export const toUpdateLineItemsOriginalCategoryClass = (transaction, transactionD
421
422
  const newLocalData = {
422
423
  ...initialSupportedTransactionDetail.transactionDetailLocalData,
423
424
  memo: transactionDetailLocalData.memo,
425
+ documentId: transactionDetailLocalData.documentId,
424
426
  lineItemById: newLineItems,
425
427
  vendorDetails: transactionDetailLocalData.vendorDetails,
426
428
  vendorUpdates: transactionDetailLocalData.vendorUpdates,
@@ -524,6 +526,7 @@ export const toSetAllLineItemsToCategoryClass = (transaction, transactionDetailL
524
526
  const newLocalData = {
525
527
  ...initialSupportedTransactionDetail.transactionDetailLocalData,
526
528
  memo: transactionDetailLocalData.memo,
529
+ documentId: transactionDetailLocalData.documentId,
527
530
  lineItemById: newLineItems,
528
531
  vendorUpdates: transactionDetailLocalData.vendorUpdates,
529
532
  vendorDetails: transactionDetailLocalData.vendorDetails,
@@ -568,6 +571,7 @@ export const toSetAllLineItemsLocalDataIsUpdateAllChecked = (transaction, transa
568
571
  const newLocalData = {
569
572
  ...initialSupportedTransactionDetail.transactionDetailLocalData,
570
573
  memo: transactionDetailLocalData.memo,
574
+ documentId: transactionDetailLocalData.documentId,
571
575
  lineItemById: newLineItems,
572
576
  vendorDetails: transactionDetailLocalData.vendorDetails,
573
577
  vendorUpdates: transactionDetailLocalData.vendorUpdates,
@@ -724,6 +728,7 @@ export const setEntityRecommendationForLineIdInLocalData = (transaction, transac
724
728
  const newLocalData = {
725
729
  ...initialSupportedTransactionDetail.transactionDetailLocalData,
726
730
  memo: transactionDetailLocalData.memo,
731
+ documentId: transactionDetailLocalData.documentId,
727
732
  lineItemById: newLineItems,
728
733
  vendorUpdates: transactionDetailLocalData.vendorUpdates,
729
734
  vendorDetails: transactionDetailLocalData.vendorDetails,
@@ -776,6 +781,7 @@ export const removeEntityRecommendationForLineIdInLocalData = (transaction, tran
776
781
  const newLocalData = {
777
782
  ...initialSupportedTransactionDetail.transactionDetailLocalData,
778
783
  memo: transactionDetailLocalData.memo,
784
+ documentId: transactionDetailLocalData.documentId,
779
785
  lineItemById: newLineItems,
780
786
  vendorDetails: transactionDetailLocalData.vendorDetails,
781
787
  vendorUpdates: transactionDetailLocalData.vendorUpdates,
@@ -881,7 +887,6 @@ export const toSetAllLineItemsToVendor = (transaction, transactionDetailLocalDat
881
887
  }
882
888
  const newLocalData = {
883
889
  ...transactionDetailLocalData,
884
- memo: transactionDetailLocalData.memo,
885
890
  lineItemById: newLineItems,
886
891
  isVendorUpdateAllChecked: true,
887
892
  };
@@ -996,6 +1001,7 @@ export const toUpdateLineItemsToOriginalVendor = (transaction, transactionDetail
996
1001
  const newLocalData = {
997
1002
  ...initialSupportedTransactionDetail.transactionDetailLocalData,
998
1003
  memo: transactionDetailLocalData.memo,
1004
+ documentId: transactionDetailLocalData.documentId,
999
1005
  lineItemById: newLineItems,
1000
1006
  isVendorUpdateAllChecked: false,
1001
1007
  latestUpdatedLineWithEntity: transactionDetailLocalData.latestUpdatedLineWithEntity,
package/lib/index.d.ts CHANGED
@@ -68,6 +68,7 @@ import { ChargeCardTransaction, ChargeCardTransactionStatus, ChargeCardTransacti
68
68
  import { ChargeCardTransactionPayload, TransactionReceiptsPayload, attachmentFilePathToAttachment } from './entity/chargeCardTransaction/chargeCardTransactionPayload';
69
69
  import { updateChargeCardTransactionAttachments } from './entity/chargeCardTransaction/chargeCardTransactionReducer';
70
70
  import { updateChargeCardTransactionFromPusher, updateChargeCardTransactionReceiptFromPusher, updateChargeCardTransactionStatusFromPusher } from './entity/chargeCardTransaction/chargeCardTransactionReducer';
71
+ import { filterChargeCardRolesWhenProductDisabled, isCardsProductEnabledOnCompany } from './entity/company/cardsVisibilityHelpers';
71
72
  import { getControllersName, getFirstControllerEmail, getFirstControllerId } from './entity/company/companyHelper';
72
73
  import { CompanyWithSchema, ControllerUserDetails, getCompanyByCompanyId, getCompanyInfoForAllCockpitCompaniesInState, getControllersForCompany } from './entity/company/companySelector';
73
74
  import { ALL_ACCOUNTING_CONNECTION_CREATION_MODES, AccountingConnectionCreationMode, Company, CompanyBillPayInfo, CompanyChargeCardInfo, CompanyConfigInfo, CompanyDebitCardInfo, CompanyFeaturesActivationInfo, CompanyIncInfo, CompanyInfo, CompanyLocaleInfo, CompanyManagementInfo, CompanyManagementUserRole, CompanyMileageConfigInfo, CompanyOnboardingAiActivationInfo, CompanyQuestionaire, CompanyReimbursementInfo, CompanyTaxInfo, CompanyZeniAccountInfo, IdentityVerificationStatus, OnboardingIdentityVerficationStatus, OnboardingInfo, OnboardingStepInfo, OnboardingStepsInfo, ParentSubsidiaryInfo, UserReimbursementInfo, isCompanyEligibleForTreasury } from './entity/company/companyStateTypes';
@@ -768,7 +769,7 @@ export { SubscriptionAddOn, SubscriptionAddOnWithSchema, SubscriptionAddOnSchema
768
769
  export { SubscriptionCoupon, SubscriptionCouponSchemaKeys };
769
770
  export { SubscriptionPlan, SubscriptionPlanSchemaKeys };
770
771
  export { SubscriptionSummary, SubscriptionSummarySchemaKeys };
771
- export { CompanyInfo, CompanyLocaleInfo, CompanyIncInfo, CompanyTaxInfo, CompanyQuestionaire, CompanyManagementInfo, CompanyManagementUserRole, Company, ParentSubsidiaryInfo, CompanyConfigInfo, CompanyReimbursementInfo, CompanyZeniAccountInfo, CompanyBillPayInfo, CompanyChargeCardInfo, CompanyDebitCardInfo, CompanyFeaturesActivationInfo, CompanyMileageConfigInfo, CompanyOnboardingAiActivationInfo, UserReimbursementInfo, OnboardingInfo, OnboardingStepsInfo, OnboardingStepInfo, AccountingConnectionCreationMode, ALL_ACCOUNTING_CONNECTION_CREATION_MODES, OnboardingIdentityVerficationStatus, IdentityVerificationStatus, isCompanyEligibleForTreasury, };
772
+ export { CompanyInfo, CompanyLocaleInfo, CompanyIncInfo, CompanyTaxInfo, CompanyQuestionaire, CompanyManagementInfo, CompanyManagementUserRole, Company, ParentSubsidiaryInfo, CompanyConfigInfo, CompanyReimbursementInfo, CompanyZeniAccountInfo, CompanyBillPayInfo, CompanyChargeCardInfo, CompanyDebitCardInfo, CompanyFeaturesActivationInfo, CompanyMileageConfigInfo, CompanyOnboardingAiActivationInfo, UserReimbursementInfo, OnboardingInfo, OnboardingStepsInfo, OnboardingStepInfo, AccountingConnectionCreationMode, ALL_ACCOUNTING_CONNECTION_CREATION_MODES, OnboardingIdentityVerficationStatus, IdentityVerificationStatus, isCompanyEligibleForTreasury, isCardsProductEnabledOnCompany, filterChargeCardRolesWhenProductDisabled, };
772
773
  export { getCompanyByCompanyId, CompanyWithSchema, getControllersForCompany, getCompanyInfoForAllCockpitCompaniesInState, ControllerUserDetails, getFirstControllerEmail, getFirstControllerId, getControllersName, };
773
774
  export type { ZeniUsersResponse } from './view/companyView/companyViewPayload';
774
775
  export { CompanyView };