@accounter/server
Version:
Accounter GraphQL server
225 lines (209 loc) • 7.96 kB
text/typescript
import { Injector } from 'graphql-modules';
import {
_DOLLAR_defs_addClientRequest_Input,
_DOLLAR_defs_updateClientRequest_Input,
} from '@accounter/green-invoice-graphql';
import type { ClientUpdateInput, UpdateBusinessInput } from '../../../__generated__/types.js';
import { CountryCode } from '../../../shared/enums.js';
import { GreenInvoiceClientProvider } from '../../app-providers/green-invoice-client.js';
import { validateClientIntegrations } from '../../financial-entities/helpers/clients.helper.js';
import { BusinessesProvider } from '../../financial-entities/providers/businesses.provider.js';
import { ClientsProvider } from '../../financial-entities/providers/clients.provider.js';
import {
IGetBusinessesByIdsResult,
IGetClientsByIdsResult,
} from '../../financial-entities/types.js';
import { countryCodeToGreenInvoiceCountry } from './green-invoice.helper.js';
function convertLocalClientToGreenInvoiceCreateClientInput(
localClient: IGetClientsByIdsResult,
localBusiness: IGetBusinessesByIdsResult,
): _DOLLAR_defs_addClientRequest_Input {
return {
/** Phone number */
phone: localBusiness.phone_number,
/** Mobile number */
// mobile: localBusiness.mobile_number,
/** Email addresses */
emails: localClient.emails,
/** Fax number */
// fax: localBusiness.fax_number,
/** Contact person name */
// contactPerson: localBusiness.contact_person,
/** Street address */
address: localBusiness.address,
/** City name */
city: localBusiness.city,
/** Zip/postal code */
zip: localBusiness.zip_code,
country: countryCodeToGreenInvoiceCountry(localBusiness.country as CountryCode),
/** Bank name */
// bankName: localBusiness.bank_name,
/** Bank branch number */
// bankBranch: localBusiness.bank_branch_number,
/** Bank account number */
// bankAccount: localBusiness.bank_account_number,
/** The client name */
name: localBusiness.name,
/** Is the client currently active or not */
active: localBusiness.is_active,
/** The client tax ID */
taxId: localBusiness.vat_number,
// paymentTerms: localClient.payment_terms,
// labels: localClient.labels,
/** Whether to send emails to the user automatically when assigning him to an invoice or not */
// send: localClient.send,
/** The client department */
// department: localClient.department,
/** The client accounting key */
accountingKey: localBusiness.sort_code?.toString(),
/** The category this client is related to */
// category: localClient.category,
/** The sub category this client is related to */
// subCategory: localClient.sub_category,
/** Client remarks for self use */
// remarks: localClient.remarks,
};
}
export async function addGreenInvoiceClient(clientId: string, injector: Injector): Promise<void> {
try {
// validate local client
const localBusinessPromise = injector
.get(BusinessesProvider)
.getBusinessByIdLoader.load(clientId);
const localClientPromise = injector.get(ClientsProvider).getClientByIdLoader.load(clientId);
const [localBusiness, localClient] = await Promise.all([
localBusinessPromise,
localClientPromise,
]);
if (!localBusiness) {
throw new Error('Business not found');
}
if (!localClient) {
throw new Error('Client not found');
}
// validate details
const greenInvoiceCreatClientInput = convertLocalClientToGreenInvoiceCreateClientInput(
localClient,
localBusiness,
);
// add to green invoice
const greenInvoiceClient = await injector
.get(GreenInvoiceClientProvider)
.createClient(greenInvoiceCreatClientInput);
if (!greenInvoiceClient?.id) {
throw new Error('Failed to create Green Invoice client');
}
const integrations = validateClientIntegrations(localClient.integrations);
// add green invoice id to local client
await injector.get(ClientsProvider).updateClient({
businessId: clientId,
integrations: {
...integrations,
greenInvoiceId: greenInvoiceClient.id,
},
});
} catch (error) {
const message = 'Error adding Green Invoice client';
console.error(`${message}: ${error}`);
throw new Error(message, { cause: error });
}
}
function pickGreenInvoiceClientFields(
businessFields: Omit<UpdateBusinessInput, 'id'> & { name: string },
clientFields: ClientUpdateInput,
): _DOLLAR_defs_updateClientRequest_Input {
const fieldsToUpdate: _DOLLAR_defs_updateClientRequest_Input = {
/** Phone number */
phone: businessFields.phoneNumber,
/** Mobile number */
// mobile: businessFields.mobile_number,
/** Email addresses */
emails: clientFields.emails ? [...clientFields.emails] : undefined,
/** Fax number */
// fax: businessFields.fax_number,
/** Contact person name */
// contactPerson: businessFields.contact_person,
/** Street address */
address: businessFields.address ?? undefined,
/** City name */
city: businessFields.city,
/** Zip/postal code */
zip: businessFields.zipCode,
country: businessFields.country
? countryCodeToGreenInvoiceCountry(businessFields.country as CountryCode)
: undefined,
/** Bank name */
// bankName: businessFields.bank_name,
/** Bank branch number */
// bankBranch: businessFields.bank_branch_number,
/** Bank account number */
// bankAccount: businessFields.bank_account_number,
/** The client name */
name: businessFields.name ?? undefined,
/** Is the client currently active or not */
active: businessFields.isActive,
/** The client tax ID */
taxId: businessFields.governmentId,
// paymentTerms: clientFields.payment_terms,
// labels: clientFields.labels,
/** Whether to send emails to the user automatically when assigning him to an invoice or not */
// send: clientFields.send,
/** The client department */
// department: clientFields.department,
/** The client accounting key */
accountingKey: businessFields.sortCode?.toString(),
/** The category this client is related to */
// category: clientFields.category,
/** The sub category this client is related to */
// subCategory: clientFields.sub_category,
/** Client remarks for self use */
// remarks: clientFields.remarks,
};
return fieldsToUpdate;
}
export async function updateGreenInvoiceClient(
clientId: string,
injector: Injector,
businessFields: UpdateBusinessInput = {},
clientFields: ClientUpdateInput = {},
): Promise<void> {
// validate local client
const localBusinessPromise = injector
.get(BusinessesProvider)
.getBusinessByIdLoader.load(clientId);
const localClientPromise = injector.get(ClientsProvider).getClientByIdLoader.load(clientId);
const [localBusiness, localClient] = await Promise.all([
localBusinessPromise,
localClientPromise,
]);
let greenInvoiceId: string | undefined;
try {
greenInvoiceId =
validateClientIntegrations(localClient?.integrations ?? {}).greenInvoiceId ?? undefined;
} catch {
// swallow errors
return;
}
if (!localBusiness?.name || !greenInvoiceId) {
// We cannot update a client in Green Invoice without its ID.
console.warn(
`Cannot update Green Invoice client: missing local business name or client ID for business${clientId}`,
);
return;
}
const fieldsToUpdate = pickGreenInvoiceClientFields(
{ ...businessFields, name: localBusiness.name },
clientFields,
);
if (Object.keys(fieldsToUpdate).length === 0) {
return;
}
const greenInvoiceClient = await injector.get(GreenInvoiceClientProvider).updateClient({
id: greenInvoiceId,
input: fieldsToUpdate,
});
if (!greenInvoiceClient?.id) {
throw new Error('Failed to create Green Invoice client');
}
return;
}