@bisondesk/core-sdk 1.0.677 → 1.0.679
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/apis/exchange-rates.d.ts +0 -3
- package/lib/apis/exchange-rates.d.ts.map +1 -1
- package/lib/apis/exchange-rates.js +0 -29
- package/lib/apis/exchange-rates.js.map +1 -1
- package/lib/apis/organization-bank-accounts.d.ts +11 -0
- package/lib/apis/organization-bank-accounts.d.ts.map +1 -0
- package/lib/apis/organization-bank-accounts.js +47 -0
- package/lib/apis/organization-bank-accounts.js.map +1 -0
- package/lib/types/intercompany-payments.d.ts.map +1 -1
- package/lib/types/intercompany-payments.js.map +1 -1
- package/lib/types/offers.d.ts +1 -2
- package/lib/types/offers.d.ts.map +1 -1
- package/lib/types/offers.js.map +1 -1
- package/lib/types/opportunities.d.ts +1 -8
- package/lib/types/opportunities.d.ts.map +1 -1
- package/lib/types/opportunities.js.map +1 -1
- package/lib/types/opportunity-payments.d.ts +0 -9
- package/lib/types/opportunity-payments.d.ts.map +1 -1
- package/lib/types/opportunity-payments.js.map +1 -1
- package/lib/types/organization-bank-accounts.d.ts +35 -0
- package/lib/types/organization-bank-accounts.d.ts.map +1 -0
- package/lib/types/organization-bank-accounts.js +9 -0
- package/lib/types/organization-bank-accounts.js.map +1 -0
- package/lib/types/payment-exports.d.ts +23 -0
- package/lib/types/payment-exports.d.ts.map +1 -0
- package/lib/types/payment-exports.js +2 -0
- package/lib/types/payment-exports.js.map +1 -0
- package/lib/types/tenants.d.ts +1 -1
- package/lib/types/tenants.d.ts.map +1 -1
- package/lib/types/tenants.js +1 -0
- package/lib/types/tenants.js.map +1 -1
- package/lib/types/transports.d.ts +1 -1
- package/lib/types/transports.d.ts.map +1 -1
- package/lib/types/transports.js +1 -1
- package/lib/types/transports.js.map +1 -1
- package/lib/types/vehicle-purchase-payments.d.ts +52 -8
- package/lib/types/vehicle-purchase-payments.d.ts.map +1 -1
- package/lib/types/vehicle-purchase-payments.js +6 -0
- package/lib/types/vehicle-purchase-payments.js.map +1 -1
- package/lib/types/vehicles.d.ts +1 -7
- package/lib/types/vehicles.d.ts.map +1 -1
- package/lib/types/vehicles.js.map +1 -1
- package/lib/utils/organization-bank-accounts.d.ts +3 -0
- package/lib/utils/organization-bank-accounts.d.ts.map +1 -0
- package/lib/utils/organization-bank-accounts.js +9 -0
- package/lib/utils/organization-bank-accounts.js.map +1 -0
- package/lib/utils/tenants.d.ts +0 -3
- package/lib/utils/tenants.d.ts.map +1 -1
- package/lib/utils/tenants.js +0 -3
- package/lib/utils/tenants.js.map +1 -1
- package/lib/utils/tenants.test.js +1 -27
- package/lib/utils/tenants.test.js.map +1 -1
- package/lib/utils/transports.d.ts +8 -4
- package/lib/utils/transports.d.ts.map +1 -1
- package/lib/utils/transports.js +13 -7
- package/lib/utils/transports.js.map +1 -1
- package/lib/utils/transports.test.d.ts +2 -0
- package/lib/utils/transports.test.d.ts.map +1 -0
- package/lib/utils/transports.test.js +40 -0
- package/lib/utils/transports.test.js.map +1 -0
- package/package.json +1 -1
- package/src/apis/exchange-rates.ts +0 -49
- package/src/apis/organization-bank-accounts.ts +123 -0
- package/src/types/intercompany-payments.ts +3 -4
- package/src/types/offers.ts +0 -2
- package/src/types/opportunities.ts +1 -15
- package/src/types/opportunity-payments.ts +0 -23
- package/src/types/organization-bank-accounts.ts +56 -0
- package/src/types/payment-exports.ts +40 -0
- package/src/types/tenants.ts +7 -6
- package/src/types/transports.ts +1 -1
- package/src/types/vehicle-purchase-payments.ts +114 -13
- package/src/types/vehicles.ts +4 -15
- package/src/utils/organization-bank-accounts.ts +19 -0
- package/src/utils/tenants.test.ts +1 -39
- package/src/utils/tenants.ts +0 -17
- package/src/utils/transports.test.ts +50 -0
- package/src/utils/transports.ts +39 -22
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/utils/opportunity-payments.d.ts +0 -3
- package/lib/utils/opportunity-payments.d.ts.map +0 -1
- package/lib/utils/opportunity-payments.js +0 -5
- package/lib/utils/opportunity-payments.js.map +0 -1
- package/lib/utils/opportunity-payments.test.d.ts +0 -2
- package/lib/utils/opportunity-payments.test.d.ts.map +0 -1
- package/lib/utils/opportunity-payments.test.js +0 -23
- package/lib/utils/opportunity-payments.test.js.map +0 -1
- package/src/types/activities.js +0 -13
- package/src/types/activities.js.map +0 -1
- package/src/types/comparables.js +0 -2
- package/src/types/comparables.js.map +0 -1
- package/src/types/crm.js +0 -58
- package/src/types/crm.js.map +0 -1
- package/src/types/dashboard.js +0 -2
- package/src/types/dashboard.js.map +0 -1
- package/src/types/definitions.js +0 -2
- package/src/types/definitions.js.map +0 -1
- package/src/types/fields.js +0 -2
- package/src/types/fields.js.map +0 -1
- package/src/types/insights.js +0 -2
- package/src/types/insights.js.map +0 -1
- package/src/types/interests.js +0 -6
- package/src/types/interests.js.map +0 -1
- package/src/types/internal-events.js +0 -18
- package/src/types/internal-events.js.map +0 -1
- package/src/types/internet-opportunities.js +0 -2
- package/src/types/internet-opportunities.js.map +0 -1
- package/src/types/internet-vehicles.js +0 -2
- package/src/types/internet-vehicles.js.map +0 -1
- package/src/types/leasing-administration.js +0 -2
- package/src/types/leasing-administration.js.map +0 -1
- package/src/types/leasing-debtors.js +0 -2
- package/src/types/leasing-debtors.js.map +0 -1
- package/src/types/leasing-search.js +0 -2
- package/src/types/leasing-search.js.map +0 -1
- package/src/types/leasing-settings.js +0 -7
- package/src/types/leasing-settings.js.map +0 -1
- package/src/types/leasing.js +0 -38
- package/src/types/leasing.js.map +0 -1
- package/src/types/marketing.js +0 -35
- package/src/types/marketing.js.map +0 -1
- package/src/types/offers.js +0 -56
- package/src/types/opportunities.js +0 -107
- package/src/types/opportunities.js.map +0 -1
- package/src/types/payments.js +0 -7
- package/src/types/picklists.js +0 -2
- package/src/types/picklists.js.map +0 -1
- package/src/types/quotes.js +0 -42
- package/src/types/recently-viewed.js +0 -2
- package/src/types/recently-viewed.js.map +0 -1
- package/src/types/reservations.js +0 -5
- package/src/types/reservations.js.map +0 -1
- package/src/types/roi-ratings.js +0 -5
- package/src/types/roi-ratings.js.map +0 -1
- package/src/types/saved-filters.js +0 -9
- package/src/types/saved-filters.js.map +0 -1
- package/src/types/search.js +0 -2
- package/src/types/search.js.map +0 -1
- package/src/types/settings.js +0 -2
- package/src/types/settings.js.map +0 -1
- package/src/types/templates.js +0 -2
- package/src/types/templates.js.map +0 -1
- package/src/types/tenants.js +0 -21
- package/src/types/tenants.js.map +0 -1
- package/src/types/user-performance.js +0 -7
- package/src/types/user-performance.js.map +0 -1
- package/src/types/utils.js +0 -2
- package/src/types/validation.js +0 -2
- package/src/types/validation.js.map +0 -1
- package/src/types/vehicle-sales.js +0 -6
- package/src/types/vehicle-sales.js.map +0 -1
- package/src/types/vehicles.js +0 -98
- package/src/types/vehicles.js.map +0 -1
- package/src/utils/leasing.js +0 -6
- package/src/utils/leasing.js.map +0 -1
- package/src/utils/opportunities.js +0 -48
- package/src/utils/opportunities.js.map +0 -1
- package/src/utils/opportunity-payments.test.ts +0 -31
- package/src/utils/opportunity-payments.ts +0 -15
package/package.json
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { XError } from '@bisondesk/commons-sdk/errors';
|
|
2
2
|
import { getAdminAuth } from '@bisondesk/commons-sdk/fetch';
|
|
3
|
-
import {
|
|
4
|
-
CurrencyConversionRequest,
|
|
5
|
-
CurrencyConversionResponse,
|
|
6
|
-
} from '@bisondesk/commons-sdk/types';
|
|
7
3
|
import fetch, { Response } from 'node-fetch';
|
|
8
4
|
import { ExchangeRate } from '../types/exchange-rates.js';
|
|
9
5
|
|
|
@@ -50,51 +46,6 @@ export const getExchangeRate = async (
|
|
|
50
46
|
throw new XError(response.statusText, { url, body, fromCurrency, toCurrency });
|
|
51
47
|
};
|
|
52
48
|
|
|
53
|
-
/** The daily rates of the rate provider, as the quote and invoice forms get them. */
|
|
54
|
-
export const getCurrencyConversionRates = async (
|
|
55
|
-
request: CurrencyConversionRequest,
|
|
56
|
-
): Promise<CurrencyConversionResponse> => {
|
|
57
|
-
const auth = await getAdminAuth();
|
|
58
|
-
const url = `${process.env.CORE_API_ORIGIN}/api/currency/rates`;
|
|
59
|
-
const response: Response = await fetch(url, {
|
|
60
|
-
method: 'POST',
|
|
61
|
-
headers: {
|
|
62
|
-
Authorization: auth,
|
|
63
|
-
'Content-Type': 'application/json',
|
|
64
|
-
},
|
|
65
|
-
body: JSON.stringify(request),
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
if (response.ok) {
|
|
69
|
-
return response.json() as any;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const body = await response.text();
|
|
73
|
-
throw new XError(response.statusText, { url, body, request });
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* The plain daily rate of `date`: how many units of `toCurrency` equal 1 unit of `fromCurrency`,
|
|
78
|
-
* without the bank-fee markup. Undefined when the provider has no rate for the pair.
|
|
79
|
-
*/
|
|
80
|
-
export const getDailyConversionRate = async (
|
|
81
|
-
fromCurrency: string,
|
|
82
|
-
toCurrency: string,
|
|
83
|
-
date?: string,
|
|
84
|
-
): Promise<string | undefined> => {
|
|
85
|
-
if (fromCurrency === toCurrency) {
|
|
86
|
-
return '1';
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const { rates } = await getCurrencyConversionRates({
|
|
90
|
-
sourceCurrency: fromCurrency,
|
|
91
|
-
targetCurrency: toCurrency,
|
|
92
|
-
date,
|
|
93
|
-
bankFeeMarkup: false,
|
|
94
|
-
});
|
|
95
|
-
return rates[toCurrency];
|
|
96
|
-
};
|
|
97
|
-
|
|
98
49
|
/**
|
|
99
50
|
* Direction-agnostic conversion multiplier: how many units of `toCurrency`
|
|
100
51
|
* equal 1 unit of `fromCurrency`. Tries a direct pair first, then falls back
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { SERVICE_ID_ADMIN_HEADER, TENANT_ID_ADMIN_HEADER } from '@bisondesk/commons-sdk/constants';
|
|
2
|
+
import { XError } from '@bisondesk/commons-sdk/errors';
|
|
3
|
+
import { cleanHeaders, getAdminAuth } from '@bisondesk/commons-sdk/fetch';
|
|
4
|
+
import { DataRecord } from '@bisondesk/commons-sdk/utils';
|
|
5
|
+
import fetch, { Response } from 'node-fetch';
|
|
6
|
+
import {
|
|
7
|
+
NewOrganizationBankAccount,
|
|
8
|
+
OrganizationBankAccount,
|
|
9
|
+
OrganizationBankAccountMeta,
|
|
10
|
+
} from '../types/organization-bank-accounts.js';
|
|
11
|
+
|
|
12
|
+
type ServiceOptions = { serviceId?: string };
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Calls an organisation bank-account route as a service. The service id becomes the user core
|
|
16
|
+
* records as having made the change.
|
|
17
|
+
*/
|
|
18
|
+
const callBankAccountsRoute = async (
|
|
19
|
+
tenantId: string,
|
|
20
|
+
path: string,
|
|
21
|
+
init: { method: string; body?: unknown },
|
|
22
|
+
opts?: ServiceOptions,
|
|
23
|
+
): Promise<Response> => {
|
|
24
|
+
const auth = await getAdminAuth();
|
|
25
|
+
const url = `${process.env.CORE_API_ORIGIN}${path}`;
|
|
26
|
+
const response: Response = await fetch(url, {
|
|
27
|
+
method: init.method,
|
|
28
|
+
headers: cleanHeaders({
|
|
29
|
+
Authorization: auth,
|
|
30
|
+
'Content-Type': init.body != null ? 'application/json' : undefined,
|
|
31
|
+
[TENANT_ID_ADMIN_HEADER]: tenantId,
|
|
32
|
+
[SERVICE_ID_ADMIN_HEADER]: opts?.serviceId,
|
|
33
|
+
}),
|
|
34
|
+
body: init.body != null ? JSON.stringify(init.body) : undefined,
|
|
35
|
+
});
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
const body = await response.text();
|
|
38
|
+
throw new XError(response.statusText, { method: init.method, url, body, tenantId, opts });
|
|
39
|
+
}
|
|
40
|
+
return response;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const bankAccountsPath = (organizationId: string) =>
|
|
44
|
+
`/api/crm/organizations/${organizationId}/bank-accounts`;
|
|
45
|
+
|
|
46
|
+
/** An organisation's bank accounts, the default first. */
|
|
47
|
+
export const listOrganizationBankAccounts = async (
|
|
48
|
+
tenantId: string,
|
|
49
|
+
organizationId: string,
|
|
50
|
+
opts?: ServiceOptions,
|
|
51
|
+
): Promise<OrganizationBankAccount[]> => {
|
|
52
|
+
const response = await callBankAccountsRoute(
|
|
53
|
+
tenantId,
|
|
54
|
+
bankAccountsPath(organizationId),
|
|
55
|
+
{ method: 'GET' },
|
|
56
|
+
opts,
|
|
57
|
+
);
|
|
58
|
+
const records = (await response.json()) as DataRecord<
|
|
59
|
+
OrganizationBankAccount,
|
|
60
|
+
OrganizationBankAccountMeta
|
|
61
|
+
>[];
|
|
62
|
+
return records.map((entry) => entry.record);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const createOrganizationBankAccount = async (
|
|
66
|
+
tenantId: string,
|
|
67
|
+
input: NewOrganizationBankAccount,
|
|
68
|
+
opts?: ServiceOptions,
|
|
69
|
+
): Promise<OrganizationBankAccount> => {
|
|
70
|
+
const { organizationId, ...details } = input;
|
|
71
|
+
const response = await callBankAccountsRoute(
|
|
72
|
+
tenantId,
|
|
73
|
+
bankAccountsPath(organizationId),
|
|
74
|
+
{ method: 'POST', body: details },
|
|
75
|
+
opts,
|
|
76
|
+
);
|
|
77
|
+
return (await response.json()) as OrganizationBankAccount;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const updateOrganizationBankAccount = async (
|
|
81
|
+
tenantId: string,
|
|
82
|
+
bankAccountId: string,
|
|
83
|
+
input: NewOrganizationBankAccount,
|
|
84
|
+
opts?: ServiceOptions,
|
|
85
|
+
): Promise<OrganizationBankAccount> => {
|
|
86
|
+
const { organizationId, ...details } = input;
|
|
87
|
+
const response = await callBankAccountsRoute(
|
|
88
|
+
tenantId,
|
|
89
|
+
`${bankAccountsPath(organizationId)}/${bankAccountId}`,
|
|
90
|
+
{ method: 'PUT', body: details },
|
|
91
|
+
opts,
|
|
92
|
+
);
|
|
93
|
+
return (await response.json()) as OrganizationBankAccount;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const deleteOrganizationBankAccount = async (
|
|
97
|
+
tenantId: string,
|
|
98
|
+
organizationId: string,
|
|
99
|
+
bankAccountId: string,
|
|
100
|
+
opts?: ServiceOptions,
|
|
101
|
+
): Promise<void> => {
|
|
102
|
+
await callBankAccountsRoute(
|
|
103
|
+
tenantId,
|
|
104
|
+
`${bankAccountsPath(organizationId)}/${bankAccountId}`,
|
|
105
|
+
{ method: 'DELETE' },
|
|
106
|
+
opts,
|
|
107
|
+
);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const setDefaultOrganizationBankAccount = async (
|
|
111
|
+
tenantId: string,
|
|
112
|
+
organizationId: string,
|
|
113
|
+
bankAccountId: string,
|
|
114
|
+
opts?: ServiceOptions,
|
|
115
|
+
): Promise<OrganizationBankAccount> => {
|
|
116
|
+
const response = await callBankAccountsRoute(
|
|
117
|
+
tenantId,
|
|
118
|
+
`${bankAccountsPath(organizationId)}/${bankAccountId}/default`,
|
|
119
|
+
{ method: 'POST' },
|
|
120
|
+
opts,
|
|
121
|
+
);
|
|
122
|
+
return (await response.json()) as OrganizationBankAccount;
|
|
123
|
+
};
|
|
@@ -13,9 +13,8 @@ export type IntercompanyPaymentHop = {
|
|
|
13
13
|
/** Deep link to the hop opportunity on the target tenant's own subdomain. */
|
|
14
14
|
opportunityUrl: string;
|
|
15
15
|
/**
|
|
16
|
-
* Currency of the amounts: the hop opportunity's quote currency
|
|
17
|
-
*
|
|
18
|
-
* carries a quote; hops missing one (malformed) are skipped.
|
|
16
|
+
* Currency of the amounts: the hop opportunity's quote currency. A reserved-stage
|
|
17
|
+
* opportunity always carries a quote; hops missing one (malformed) are skipped.
|
|
19
18
|
*/
|
|
20
19
|
currency: string;
|
|
21
20
|
vehicle: {
|
|
@@ -33,7 +32,7 @@ export type IntercompanyPaymentHop = {
|
|
|
33
32
|
* total payment before delivery). Absent until that hop's quote is manager-accepted.
|
|
34
33
|
*/
|
|
35
34
|
expectedTotal?: string;
|
|
36
|
-
/** Sum of the hop opportunity's non-deleted payment amounts
|
|
35
|
+
/** Sum of the hop opportunity's non-deleted payment amounts. */
|
|
37
36
|
paid: string;
|
|
38
37
|
};
|
|
39
38
|
|
package/src/types/offers.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
SearchVehicle,
|
|
10
10
|
VehicleExternalInfo,
|
|
11
11
|
VehicleInternalInfo,
|
|
12
|
-
VehiclePurchaseDealForeign,
|
|
13
12
|
VehiclePurchaseDealStatus,
|
|
14
13
|
VehiclePurchaseDeliveryType,
|
|
15
14
|
} from './vehicles.js';
|
|
@@ -331,7 +330,6 @@ export type OfferPurchase = {
|
|
|
331
330
|
| VehiclePurchaseDealStatus.Marketing;
|
|
332
331
|
costs: {
|
|
333
332
|
purchase: string;
|
|
334
|
-
foreign?: VehiclePurchaseDealForeign;
|
|
335
333
|
purchaseVatPercentage: string;
|
|
336
334
|
internalGarage?: string;
|
|
337
335
|
externalGarage?: string;
|
|
@@ -251,23 +251,8 @@ export type OpportunityUpdate = {
|
|
|
251
251
|
};
|
|
252
252
|
|
|
253
253
|
export type OpportunityPaymentSummary = {
|
|
254
|
-
/** Branch currency. */
|
|
255
254
|
total: string;
|
|
256
|
-
/** Sum of `amount` over the payments, in branch currency. */
|
|
257
255
|
paid: string;
|
|
258
|
-
/**
|
|
259
|
-
* The same pair in the quote's alternative currency, present when the branch can be paid in it.
|
|
260
|
-
* `paid` sums the payments that arrived in that currency.
|
|
261
|
-
*/
|
|
262
|
-
foreign?: {
|
|
263
|
-
total: string;
|
|
264
|
-
paid: string;
|
|
265
|
-
currencyCode: string;
|
|
266
|
-
exchangeRate: string;
|
|
267
|
-
};
|
|
268
|
-
/** Fully paid when either currency reaches its total. */
|
|
269
|
-
status: OpportunityPaymentStatus;
|
|
270
|
-
percentagePaid: string;
|
|
271
256
|
entries: DataRecord<OpportunityPayment>[];
|
|
272
257
|
};
|
|
273
258
|
|
|
@@ -536,6 +521,7 @@ export type HpLeasingDealRunDataCi = HpLeasingDealRunDataBase & {
|
|
|
536
521
|
dueeDuLeasingEnMois: number;
|
|
537
522
|
travauxHorsNormesNecessaire: boolean;
|
|
538
523
|
descriptionDesTravauxHorsNormes: string;
|
|
524
|
+
prixTravaexSupplementaire: string;
|
|
539
525
|
};
|
|
540
526
|
|
|
541
527
|
export type HpLeasingDealRequest = {
|
|
@@ -7,27 +7,8 @@ export enum OpportunityPaymentActions {
|
|
|
7
7
|
|
|
8
8
|
export const OPPORTUNITY_PAYMENT_NOTIFICATION_ORIGIN = 'opportunity-payment-notification';
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* The money as it arrived, when it arrived in the quote's alternative currency. `amount` then
|
|
12
|
-
* holds its value in branch currency: `foreign.amount × foreign.exchangeRate`.
|
|
13
|
-
*/
|
|
14
|
-
export type OpportunityPaymentForeign = {
|
|
15
|
-
amount: string;
|
|
16
|
-
currencyCode: string;
|
|
17
|
-
/** Branch currency units per 1 unit of `currencyCode`, the quote's rate. */
|
|
18
|
-
exchangeRate: string;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/** What a user sends for a payment in another currency. The backend takes the rate from the quote
|
|
22
|
-
* and derives `amount`. */
|
|
23
|
-
export type OpportunityPaymentForeignRequest = Pick<
|
|
24
|
-
OpportunityPaymentForeign,
|
|
25
|
-
'amount' | 'currencyCode'
|
|
26
|
-
>;
|
|
27
|
-
|
|
28
10
|
type BaseOpportunityPayment = {
|
|
29
11
|
opportunityId: string;
|
|
30
|
-
/** Branch currency. */
|
|
31
12
|
amount: string;
|
|
32
13
|
description?: string;
|
|
33
14
|
vehicleId: string;
|
|
@@ -43,7 +24,6 @@ export type NewOpportunityPayment = BaseOpportunityPayment & {
|
|
|
43
24
|
deletedAt?: undefined;
|
|
44
25
|
deletedBy?: undefined;
|
|
45
26
|
paidAt: string;
|
|
46
|
-
foreign?: OpportunityPaymentForeignRequest;
|
|
47
27
|
};
|
|
48
28
|
|
|
49
29
|
export type OpportunityPayment = BaseOpportunityPayment & {
|
|
@@ -55,14 +35,11 @@ export type OpportunityPayment = BaseOpportunityPayment & {
|
|
|
55
35
|
deletedAt?: string;
|
|
56
36
|
deletedBy?: string;
|
|
57
37
|
paidAt?: string;
|
|
58
|
-
foreign?: OpportunityPaymentForeign;
|
|
59
38
|
};
|
|
60
39
|
|
|
61
40
|
export type OpportunityPaymentUpdate = {
|
|
62
41
|
description?: string;
|
|
63
42
|
amount?: string;
|
|
64
|
-
/** `null` turns the payment back into a branch currency payment. */
|
|
65
|
-
foreign?: OpportunityPaymentForeignRequest | null;
|
|
66
43
|
paidAt?: string;
|
|
67
44
|
};
|
|
68
45
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { BankAccountDetails } from '@bisondesk/commons-sdk/bank-accounts';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* An accountant's confirmation of one account number. It only counts while the account still
|
|
5
|
+
* holds that number, so trust never carries over to a new number however the account was edited.
|
|
6
|
+
*/
|
|
7
|
+
export type OrganizationBankAccountVerification = {
|
|
8
|
+
accountNumber: string;
|
|
9
|
+
verifiedBy: string;
|
|
10
|
+
verifiedAt: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export enum OrganizationBankAccountActions {
|
|
14
|
+
VERIFY = 'verify',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export enum OrganizationBankAccountActionBlockerCode {
|
|
18
|
+
CHANGED_NEEDS_VERIFICATION = 'changed_needs_verification',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type OrganizationBankAccountActionBlocker = {
|
|
22
|
+
code: OrganizationBankAccountActionBlockerCode;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Why an action the user would otherwise see is refused right now. A missing permission hides the
|
|
27
|
+
* action instead.
|
|
28
|
+
*/
|
|
29
|
+
export type OrganizationBankAccountBlockedAction = {
|
|
30
|
+
action: OrganizationBankAccountActions;
|
|
31
|
+
reasons: OrganizationBankAccountActionBlocker[];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type OrganizationBankAccountMeta = {
|
|
35
|
+
blockedActions: OrganizationBankAccountBlockedAction[];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type NewOrganizationBankAccount = BankAccountDetails & {
|
|
39
|
+
organizationId: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* An organisation's bank account for outgoing SEPA transfers, never shared across companies. An
|
|
44
|
+
* organisation can hold several; at most one is its `default`, the one payment exports pay to.
|
|
45
|
+
* Editing the account number or holder name clears the manual verification, so a valid checksum is
|
|
46
|
+
* never mistaken for a confirmed account holder.
|
|
47
|
+
*/
|
|
48
|
+
export type OrganizationBankAccount = NewOrganizationBankAccount & {
|
|
49
|
+
id: string;
|
|
50
|
+
default?: boolean;
|
|
51
|
+
createdAt: string;
|
|
52
|
+
createdBy: string;
|
|
53
|
+
modifiedAt: string;
|
|
54
|
+
modifiedBy: string;
|
|
55
|
+
verification?: OrganizationBankAccountVerification;
|
|
56
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { BankAccountDetails } from '@bisondesk/commons-sdk/bank-accounts';
|
|
2
|
+
import { AttachmentValue } from '@bisondesk/commons-sdk/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The transfer details of one payment, frozen at export time. A later edit to the payment or the
|
|
6
|
+
* supplier bank account must not rewrite what the sent file said, so the export keeps its own copy
|
|
7
|
+
* of every value that went into the XML. It also records the payment batch the payment was sent to
|
|
8
|
+
* processing in, so the export is a self-contained audit record even though one file can span
|
|
9
|
+
* several batches.
|
|
10
|
+
*/
|
|
11
|
+
export type PaymentExportLine = {
|
|
12
|
+
paymentId: string;
|
|
13
|
+
vehicleId: string;
|
|
14
|
+
amount: string;
|
|
15
|
+
creditor: BankAccountDetails;
|
|
16
|
+
paymentBatchId: string;
|
|
17
|
+
transferReference?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type NewPaymentExport = {
|
|
21
|
+
/** Single execution date (`yyyy-MM-dd`) written to the file's `ReqdExctnDt`. */
|
|
22
|
+
executionDate: string;
|
|
23
|
+
/** Σ of the exported line amounts (string; computed with decimal arithmetic). */
|
|
24
|
+
totalAmount: string;
|
|
25
|
+
paymentIds: string[];
|
|
26
|
+
lines: PaymentExportLine[];
|
|
27
|
+
/** The generated SEPA file, stored in S3 and re-downloadable from Processing. */
|
|
28
|
+
xmlFile: AttachmentValue;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A generated SEPA file for a selection of Processing payments, plus the frozen record of exactly what
|
|
33
|
+
* was sent. Re-downloading serves the same file and never re-exports; a payment cancelled out of the
|
|
34
|
+
* file returns to Allowed and leaves this record intact.
|
|
35
|
+
*/
|
|
36
|
+
export type PaymentExport = NewPaymentExport & {
|
|
37
|
+
id: string;
|
|
38
|
+
exportedAt: string;
|
|
39
|
+
exportedBy: string;
|
|
40
|
+
};
|
package/src/types/tenants.ts
CHANGED
|
@@ -55,6 +55,13 @@ export enum TenantModule {
|
|
|
55
55
|
Intercompany = 'intercompany',
|
|
56
56
|
Opportunities = 'opportunities',
|
|
57
57
|
Offers = 'offers',
|
|
58
|
+
/**
|
|
59
|
+
* The tenant pays suppliers through Isabel file exports (SEPA transfer files). It grants the
|
|
60
|
+
* export itself and the verification of the supplier bank accounts it pays to, and requires those
|
|
61
|
+
* account numbers to be valid IBANs. Without it, Processing payments are simply marked paid, and
|
|
62
|
+
* a bank account can hold any account number.
|
|
63
|
+
*/
|
|
64
|
+
PaymentExports = 'payment_exports',
|
|
58
65
|
Vehicles = 'vehicles',
|
|
59
66
|
Tasks = 'tasks',
|
|
60
67
|
TrackAndTrace = 'track_and_trace',
|
|
@@ -148,12 +155,6 @@ export type Branch = {
|
|
|
148
155
|
exactAccounting?: boolean;
|
|
149
156
|
accounting?: AccountingProvider;
|
|
150
157
|
currency: string;
|
|
151
|
-
/**
|
|
152
|
-
* The currencies money moves in at this branch, its own `currency` included. Customer payments,
|
|
153
|
-
* purchase prices, supplier invoice drafts and Exact bookings are supported in these currencies
|
|
154
|
-
* only. Absent = the branch's own `currency` only. Set by script.
|
|
155
|
-
*/
|
|
156
|
-
paymentCurrencies?: [string, ...string[]];
|
|
157
158
|
adminNumberPrefix: string;
|
|
158
159
|
stockNumberPrefix: string;
|
|
159
160
|
vatNumber: string;
|
package/src/types/transports.ts
CHANGED
|
@@ -340,7 +340,7 @@ export const KANBAN_TRANSPORT_ITEM_FIELDS = [
|
|
|
340
340
|
'org.name',
|
|
341
341
|
'org.countryCode',
|
|
342
342
|
'org.externalId',
|
|
343
|
-
'opportunity.
|
|
343
|
+
'opportunity.branch',
|
|
344
344
|
'purchase.logistics.status',
|
|
345
345
|
'purchase.logistics.availableWeek',
|
|
346
346
|
'purchase.logistics.pickupAddress',
|
|
@@ -1,41 +1,142 @@
|
|
|
1
1
|
import { BaseEvent } from './internal-events.js';
|
|
2
|
+
import { OrganizationBankAccountActions } from './organization-bank-accounts.js';
|
|
2
3
|
import { SearchVehicle } from './vehicles.js';
|
|
3
4
|
|
|
4
5
|
export const VEHICLE_PURCHASE_PAYMENT_ALLOWED_NOTIFICATION_ORIGIN =
|
|
5
6
|
'vehicle-purchase-payment-allowed-notification';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* The stage a supplier payment sits at, driving the Unpaid/Allowed/Processing/Executed tabs.
|
|
10
|
+
* A payment only ever moves forward: an authorised payment is `allowed`; sending it to processing
|
|
11
|
+
* groups it into a payment batch and hands it to accounting (`processing`), which exports it
|
|
12
|
+
* to the Isabel bank file; marking it paid moves it to `executed`.
|
|
13
|
+
* (`unpaid` is not a stage — it is an agreed purchase with an amount still to authorise.)
|
|
10
14
|
*/
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
};
|
|
15
|
+
export enum PaymentStage {
|
|
16
|
+
Allowed = 'allowed',
|
|
17
|
+
Processing = 'processing',
|
|
18
|
+
Executed = 'executed',
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
export type NewVehiclePurchasePayment = {
|
|
19
22
|
vehicleId: string;
|
|
20
|
-
/** Branch currency. Derived from `foreign` when the purchase is priced in another currency. */
|
|
21
23
|
amount: string;
|
|
22
|
-
/** The backend takes the rate from the purchase. */
|
|
23
|
-
foreign?: Pick<VehiclePurchasePaymentForeign, 'amount' | 'currencyCode'>;
|
|
24
24
|
description?: string;
|
|
25
25
|
paidAt?: string;
|
|
26
26
|
paidBy?: string;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
export type VehiclePurchasePayment =
|
|
29
|
+
export type VehiclePurchasePayment = NewVehiclePurchasePayment & {
|
|
30
30
|
id: string;
|
|
31
31
|
createdBy: string;
|
|
32
32
|
createdAt: string;
|
|
33
|
-
|
|
33
|
+
stage: PaymentStage;
|
|
34
|
+
/** Manual settlement priority within the Allowed tab; lower is paid first. */
|
|
35
|
+
priority: number;
|
|
36
|
+
/** Set once the payment has been exported; links it to its payment export. */
|
|
37
|
+
exportId?: string;
|
|
38
|
+
/** The payment batch this payment was sent to processing in; unset while Allowed, and on payments
|
|
39
|
+
* marked paid straight from Allowed. */
|
|
40
|
+
paymentBatchId?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Supplier-facing communication that becomes the SEPA transfer's remittance information (`RmtInf`),
|
|
43
|
+
* so the supplier can reconcile the payment to an invoice. Editable while Processing and not yet
|
|
44
|
+
* exported; prefilled from the latest purchase invoice. This is not the file's per-line
|
|
45
|
+
* `EndToEndId`.
|
|
46
|
+
*/
|
|
47
|
+
transferReference?: string;
|
|
48
|
+
/** Who sent the payment to processing, and when — set at the Allowed → Processing step. */
|
|
49
|
+
sentToProcessingBy?: string;
|
|
50
|
+
sentToProcessingAt?: string;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* One send to processing: the Allowed payments an accountant moved to Processing together, and who
|
|
55
|
+
* sent them. The Processing tab groups its rows by batch. A batch holds no amount of its own; its
|
|
56
|
+
* total is the sum of the payments still in it.
|
|
57
|
+
*/
|
|
58
|
+
export type PaymentBatch = {
|
|
59
|
+
id: string;
|
|
60
|
+
createdAt: string;
|
|
61
|
+
createdBy: string;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Whether a payment's supplier can be paid in an export. Mirrors the export gate: a transfer needs a
|
|
66
|
+
* supplier bank account that carries an IBAN and holder name and has been verified. Shown as an
|
|
67
|
+
* export-blocked marker on the Processing rows, where the accountant clears it before exporting.
|
|
68
|
+
* (The invoice / pro-forma document half of the gate is not reflected here — its source is a Q3
|
|
69
|
+
* residual the backend export gate also defers.)
|
|
70
|
+
*
|
|
71
|
+
* The bank account is the supplier's default one, `bankAccountId`, which is the account an export
|
|
72
|
+
* pays. `bankAccountActions` lists what the current user may do on it, so a row can point out the
|
|
73
|
+
* accounts they can verify themselves. Once the account number or holder name changed, verify is
|
|
74
|
+
* left out for accountants, and for whichever Senior Accountant made the change (four-eyes).
|
|
75
|
+
*/
|
|
76
|
+
export type PaymentExportChecks = {
|
|
77
|
+
bankAccountId?: string;
|
|
78
|
+
hasBankAccount: boolean;
|
|
79
|
+
bankAccountVerified: boolean;
|
|
80
|
+
bankAccountActions: OrganizationBankAccountActions[];
|
|
34
81
|
};
|
|
35
82
|
|
|
36
83
|
export type VehiclePurchasePaymentBff = {
|
|
37
84
|
payment: VehiclePurchasePayment;
|
|
38
85
|
vehicle: SearchVehicle;
|
|
86
|
+
/** Name of the supplier organisation (`vehicle.purchase.organizationId`), resolved for display. */
|
|
87
|
+
supplierName?: string;
|
|
88
|
+
/** Export checks on the supplier bank account; filled for the Processing list only. */
|
|
89
|
+
exportChecks?: PaymentExportChecks;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* A row on the Unpaid tab: an agreed purchase that still has an amount to authorise for payment.
|
|
94
|
+
* Derived from the purchase deal and the payments already authorised, not a payment record.
|
|
95
|
+
*/
|
|
96
|
+
export type UnpaidPurchase = {
|
|
97
|
+
vehicle: SearchVehicle;
|
|
98
|
+
/** The agreed purchase price including VAT (`deal.purchase` grossed up by `deal.purchaseVatRate`),
|
|
99
|
+
* so it matches the VAT-inclusive cost the vehicle purchase tab authorises against. */
|
|
100
|
+
purchaseAmount: string;
|
|
101
|
+
/** Sum of amounts already authorised (payments in any stage) for this vehicle. */
|
|
102
|
+
allowedAmount: string;
|
|
103
|
+
/** Sum of the authorised amounts already settled (payments in Executed) for this vehicle. */
|
|
104
|
+
paidAmount: string;
|
|
105
|
+
/** `purchaseAmount − allowedAmount`; always greater than zero for rows shown here. */
|
|
106
|
+
remainingAmount: string;
|
|
107
|
+
/** Due date of the purchase invoice. */
|
|
108
|
+
invoiceDueDate?: string;
|
|
109
|
+
/** Name of the supplier organisation (`vehicle.purchase.organizationId`), resolved for display. */
|
|
110
|
+
supplierName?: string;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/** Body of the export request: the Processing payments to put in one file, the paying account, and the execution date. */
|
|
114
|
+
export type ExportPaymentsRequest = {
|
|
115
|
+
paymentIds: string[];
|
|
116
|
+
/** The bank account (from documents settings) to pay the file from — the file's debtor. */
|
|
117
|
+
debtorBankAccountId: string;
|
|
118
|
+
/** Single execution date (`yyyy-MM-dd`) written to `ReqdExctnDt`; defaults to today. */
|
|
119
|
+
executionDate?: string;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/** Body of the mark-paid request: the payments (Allowed or Processing) to settle in one call. */
|
|
123
|
+
export type MarkPaymentsPaidRequest = {
|
|
124
|
+
paymentIds: string[];
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/** Body of the send-to-processing request: the Allowed payments to send together as one batch. */
|
|
128
|
+
export type SendPaymentsToProcessingRequest = {
|
|
129
|
+
paymentIds: string[];
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* How many rows sit behind each payment tab, for the tab counters. Executed is unbounded and has no
|
|
134
|
+
* counter, so it is left out.
|
|
135
|
+
*/
|
|
136
|
+
export type PurchasePaymentCounts = {
|
|
137
|
+
unpaid: number;
|
|
138
|
+
allowed: number;
|
|
139
|
+
processing: number;
|
|
39
140
|
};
|
|
40
141
|
|
|
41
142
|
export type VehiclePurchasePaymentCreateEvent = {
|
package/src/types/vehicles.ts
CHANGED
|
@@ -170,7 +170,6 @@ export type NewVehicleRequest = {
|
|
|
170
170
|
dealStatus: VehiclePurchaseDealStatus;
|
|
171
171
|
costs: {
|
|
172
172
|
purchase: string;
|
|
173
|
-
foreign?: VehiclePurchaseDealForeign;
|
|
174
173
|
purchaseVatPercentage: string;
|
|
175
174
|
commission?: string;
|
|
176
175
|
externalTransport?: string;
|
|
@@ -812,18 +811,6 @@ export type VehiclePriceUpdateResponse =
|
|
|
812
811
|
errors: VehiclePriceUpdateError[];
|
|
813
812
|
};
|
|
814
813
|
|
|
815
|
-
/**
|
|
816
|
-
* The price the supplier asked, in the supplier's currency: one of the payment currencies of the
|
|
817
|
-
* vehicle's branch. The purchase's `deal.purchase` is then `purchase × exchangeRate`, and payments
|
|
818
|
-
* are authorized in `currencyCode`.
|
|
819
|
-
*/
|
|
820
|
-
export type VehiclePurchaseDealForeign = {
|
|
821
|
-
purchase: string; // exclusive VAT
|
|
822
|
-
currencyCode: string;
|
|
823
|
-
/** Branch currency units per 1 unit of `currencyCode`. */
|
|
824
|
-
exchangeRate: string;
|
|
825
|
-
};
|
|
826
|
-
|
|
827
814
|
export type VehiclePurchase = {
|
|
828
815
|
organizationId: string;
|
|
829
816
|
contactId: string;
|
|
@@ -859,13 +846,15 @@ export type VehiclePurchase = {
|
|
|
859
846
|
checkedInBy?: string;
|
|
860
847
|
};
|
|
861
848
|
|
|
849
|
+
/** Due date of the supplier purchase invoice; editable from the payments page. */
|
|
850
|
+
invoiceDueDate?: string;
|
|
851
|
+
|
|
862
852
|
deal: {
|
|
863
853
|
status: VehiclePurchaseDealStatus; // partially set by the user, if there are payments then it is set automatically by the backend
|
|
864
854
|
readyToDeliver?: boolean;
|
|
865
855
|
|
|
866
856
|
purchaseVatRate?: string;
|
|
867
|
-
purchase?: string; // exclusive VAT
|
|
868
|
-
foreign?: VehiclePurchaseDealForeign;
|
|
857
|
+
purchase?: string; // exclusive VAT
|
|
869
858
|
|
|
870
859
|
bonus?: string; // sometimes manufacturers pay us a bonus when we reach a target
|
|
871
860
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { normalizeIban } from '@bisondesk/commons-sdk/iban';
|
|
2
|
+
import { OrganizationBankAccount } from '../types/organization-bank-accounts.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Whether an organisation's bank account can be paid: it carries a verification, and that
|
|
6
|
+
* verification was given for the account number the account holds now. A verification recorded
|
|
7
|
+
* without an account number, or for a different one, does not count.
|
|
8
|
+
*
|
|
9
|
+
* Shared so the export gate and the Processing rows read one rule.
|
|
10
|
+
*/
|
|
11
|
+
export const isOrganizationBankAccountVerified = (
|
|
12
|
+
account: OrganizationBankAccount | undefined,
|
|
13
|
+
): boolean => {
|
|
14
|
+
const verifiedAccountNumber = account?.verification?.accountNumber;
|
|
15
|
+
if (account == null || verifiedAccountNumber == null) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return normalizeIban(verifiedAccountNumber) === normalizeIban(account.accountNumber);
|
|
19
|
+
};
|