@accounter/server
Version:
Accounter GraphQL server
1,238 lines • 46.8 kB
JavaScript
import { GraphQLError } from 'graphql';
import { CountryCode, Currency, DocumentType } from '../../../shared/enums.js';
import { formatCurrency, hashStringToInt } from '../../../shared/helpers/index.js';
import { CloudinaryProvider } from '../../app-providers/cloudinary.js';
import { GreenInvoiceClientProvider } from '../../app-providers/green-invoice-client.js';
import { ChargesProvider } from '../../charges/providers/charges.provider.js';
import { DocumentsProvider } from '../../documents/providers/documents.provider.js';
import { IssuedDocumentsProvider } from '../../documents/providers/issued-documents.provider.js';
import { validateClientIntegrations } from '../../financial-entities/helpers/clients.helper.js';
import { ClientsProvider } from '../../financial-entities/providers/clients.provider.js';
export function normalizeGreenInvoiceDocumentType(rawType) {
if (!rawType) {
return DocumentType.Unprocessed;
}
if (typeof rawType === 'string' && rawType.startsWith('_')) {
const int = parseInt(rawType.replace('_', ''));
if (Number.isInteger(int)) {
rawType = int;
}
}
switch (rawType) {
case 20:
// חשבון / אישור תשלום
return DocumentType.Invoice;
case 300:
// חשבונית עסקה
return DocumentType.Proforma;
case 305:
// חשבונית מס
return DocumentType.Invoice;
case 320:
// חשבונית מס\קבלה
return DocumentType.InvoiceReceipt;
case 330:
// חשבונית זיכוי
return DocumentType.CreditInvoice;
case 400:
// קבלה
return DocumentType.Receipt;
case 405:
// קבלה על תרומה
return DocumentType.Unprocessed;
default:
console.log(`Got a new document type from Green Invoice: ${rawType}`);
return DocumentType.Unprocessed;
}
}
export function getGreenInvoiceDocumentType(documentType) {
switch (documentType) {
case DocumentType.Invoice:
return '_305';
case DocumentType.Proforma:
return '_300';
case DocumentType.InvoiceReceipt:
return '_320';
case DocumentType.CreditInvoice:
return '_330';
case DocumentType.Receipt:
return '_400';
default:
throw new Error(`Unsupported document type: ${documentType}`);
}
}
export function getTypeFromGreenInvoiceDocument(documentType) {
switch (documentType) {
case '_305':
return DocumentType.Invoice;
case '_300':
return DocumentType.Proforma;
case '_320':
return DocumentType.InvoiceReceipt;
case '_330':
return DocumentType.CreditInvoice;
case '_400':
return DocumentType.Receipt;
default:
throw new Error(`Unsupported document type: ${documentType}`);
}
}
export function getDocumentNameFromGreenInvoiceType(documentType) {
switch (documentType) {
case '_305':
return 'Tax Invoice';
case '_300':
return 'Proforma Invoice';
case '_320':
return 'Invoice / Receipt';
case '_330':
return 'Credit Note';
case '_400':
return 'Receipt';
default:
throw new Error(`Unsupported document type: ${documentType}`);
}
}
export function getGreenInvoiceDocumentLanguage(language) {
switch (language) {
case 'HEBREW':
return 'he';
case 'ENGLISH':
return 'en';
default:
throw new Error(`Unsupported document language: ${language}`);
}
}
export function getLanguageFromGreenInvoiceDocument(lang) {
switch (lang) {
case 'he':
return 'HEBREW';
case 'en':
return 'ENGLISH';
default:
throw new Error(`Unsupported document language: ${lang}`);
}
}
export function getGreenInvoiceDocumentVatType(vatType) {
switch (vatType) {
case 'DEFAULT':
return '_0';
case 'EXEMPT':
return '_1';
case 'MIXED':
return '_2';
default:
throw new Error(`Unsupported VAT type: ${vatType}`);
}
}
export function getVatTypeFromGreenInvoiceDocument(vatType) {
switch (vatType) {
case '_0':
return 'DEFAULT';
case '_1':
return 'EXEMPT';
case '_2':
return 'MIXED';
default:
throw new Error(`Unsupported VAT type: ${vatType}`);
}
}
export function getGreenInvoiceDocumentDiscountType(discountType) {
switch (discountType) {
case 'PERCENTAGE':
return 'percentage';
case 'SUM':
return 'sum';
default:
throw new Error(`Unsupported discount type: ${discountType}`);
}
}
export function getGreenInvoiceDocumentPaymentType(type) {
switch (type) {
case 'TAX_DEDUCTION':
return 'NEGATIVE_1';
case 'CASH':
return '_1';
case 'CHEQUE':
return '_2';
case 'CREDIT_CARD':
return '_3';
case 'WIRE_TRANSFER':
return '_4';
case 'PAYPAL':
return '_5';
case 'OTHER_DEDUCTION':
return '_9';
case 'PAYMENT_APP':
return '_10';
case 'OTHER':
return '_11';
default:
throw new Error(`Unsupported payment type: ${type}`);
}
}
export function getTypeFromGreenInvoiceDocumentPayment(type) {
switch (type) {
case 'NEGATIVE_1':
return 'TAX_DEDUCTION';
case '_1':
return 'CASH';
case '_2':
return 'CHEQUE';
case '_3':
return 'CREDIT_CARD';
case '_4':
return 'WIRE_TRANSFER';
case '_5':
return 'PAYPAL';
case '_9':
return 'OTHER_DEDUCTION';
case '_10':
return 'PAYMENT_APP';
case '_11':
return 'OTHER';
default:
throw new Error(`Unsupported payment type: ${type}`);
}
}
// export function getGreenInvoiceDocumentPaymentSubType(
// subType: GreenInvoicePaymentSubType,
// ): query_getDocument_payment_items_subType {
// switch (subType) {
// case 'BITCOIN':
// return '_1';
// case 'BUYME_VOUCHER':
// return '_7';
// case 'ETHEREUM':
// return '_6';
// case 'GIFT_CARD':
// return '_4';
// case 'MONEY_EQUAL':
// return '_2';
// case 'NII_EMPLOYEE_DEDUCTION':
// return '_5';
// case 'PAYONEER':
// return '_8';
// case 'V_CHECK':
// return '_3';
// default:
// throw new Error(`Unsupported payment sub-type: ${subType}`);
// }
// }
// export function getSubTypeFromGreenInvoiceDocumentPayment(
// subType: query_getDocument_payment_items_subType,
// ): GreenInvoicePaymentSubType {
// switch (subType) {
// case '_1':
// return 'BITCOIN';
// case '_7':
// return 'BUYME_VOUCHER';
// case '_6':
// return 'ETHEREUM';
// case '_4':
// return 'GIFT_CARD';
// case '_2':
// return 'MONEY_EQUAL';
// case '_5':
// return 'NII_EMPLOYEE_DEDUCTION';
// case '_8':
// return 'PAYONEER';
// case '_3':
// return 'V_CHECK';
// default:
// throw new Error(`Unsupported payment sub-type: ${subType}`);
// }
// }
// export function getGreenInvoiceDocumentPaymentAppType(
// appType: GreenInvoicePaymentAppType,
// ): query_getDocument_payment_items_appType {
// switch (appType) {
// case 'APPLE_PAY':
// return '_6';
// case 'BIT':
// return '_1';
// case 'CULO':
// return '_4';
// case 'GOOGLE_PAY':
// return '_5';
// case 'PAYBOX':
// return '_3';
// case 'PAY_BY_PEPPER':
// return '_2';
// default:
// throw new Error(`Unsupported payment app type: ${appType}`);
// }
// }
// export function getPaymentAppTypeFromGreenInvoiceDocument(
// appType: query_getDocument_payment_items_appType,
// ): GreenInvoicePaymentAppType {
// switch (appType) {
// case '_6':
// return 'APPLE_PAY';
// case '_1':
// return 'BIT';
// case '_4':
// return 'CULO';
// case '_5':
// return 'GOOGLE_PAY';
// case '_3':
// return 'PAYBOX';
// case '_2':
// return 'PAY_BY_PEPPER';
// default:
// throw new Error(`Unsupported payment app type: ${appType}`);
// }
// }
export function getGreenInvoiceDocumentPaymentCardType(cardType) {
switch (cardType) {
case 'AMERICAN_EXPRESS':
return '_4';
case 'DINERS':
return '_5';
case 'ISRACARD':
return '_1';
case 'MASTERCARD':
return '_3';
// case 'UNKNOWN':
// return '_0'; // TODO: why is this not supported?
case 'VISA':
return '_2';
default:
throw new Error(`Unsupported payment card type: ${cardType}`);
}
}
export function getCardTypeFromGreenInvoiceDocumentPayment(cardType) {
switch (cardType) {
case '_4':
return 'AMERICAN_EXPRESS';
case '_5':
return 'DINERS';
case '_1':
return 'ISRACARD';
case '_3':
return 'MASTERCARD';
// case '_0': // TODO: why is this not supported?
// return 'UNKNOWN';
case '_2':
return 'VISA';
default:
throw new Error(`Unsupported payment card type: ${cardType}`);
}
}
// export function getGreenInvoiceDocumentPaymentDealType(
// dealType: GreenInvoicePaymentDealType,
// ): query_getDocument_payment_items_dealType {
// switch (dealType) {
// case 'CREDIT':
// return '_3';
// case 'DEFERRED':
// return '_4';
// case 'OTHER':
// return '_5';
// case 'PAYMENTS':
// return '_2';
// case 'RECURRING':
// return '_6';
// case 'STANDARD':
// return '_1';
// default:
// throw new Error(`Unsupported payment deal type: ${dealType}`);
// }
// }
// export function getDealTypeFromGreenInvoiceDocumentPayment(
// dealType: query_getDocument_payment_items_dealType,
// ): GreenInvoicePaymentDealType {
// switch (dealType) {
// case '_3':
// return 'CREDIT';
// case '_4':
// return 'DEFERRED';
// case '_5':
// return 'OTHER';
// case '_2':
// return 'PAYMENTS';
// case '_6':
// return 'RECURRING';
// case '_1':
// return 'STANDARD';
// default:
// throw new Error(`Unsupported payment deal type: ${dealType}`);
// }
// }
export function getGreenInvoiceDocumentLinkType(linkType) {
switch (linkType) {
case 'CANCEL':
return 'CANCEL';
case 'LINK':
return 'LINK';
default:
throw new Error(`Unsupported link type: ${linkType}`);
}
}
export function convertCurrencyToGreenInvoice(currency) {
switch (currency) {
case Currency.Aud:
return 'AUD';
case Currency.Cad:
return 'CAD';
case Currency.Eur:
return 'EUR';
case Currency.Gbp:
return 'GBP';
case Currency.Ils:
return 'ILS';
case Currency.Jpy:
return 'JPY';
case Currency.Sek:
return 'SEK';
case Currency.Usd:
return 'USD';
case Currency.Eth:
case Currency.Grt:
case Currency.Usdc:
throw new Error(`Crypto currency (${currency}) is not supported`);
default:
throw new Error(`Unsupported currency: ${currency}`);
}
}
export function greenInvoiceCountryToCountryCode(country) {
const greenInvoiceToCountryCodeMap = {
AD: CountryCode.Andorra,
AE: CountryCode['United Arab Emirates (the)'],
AF: CountryCode.Afghanistan,
AG: CountryCode['Antigua and Barbuda'],
AI: CountryCode.Anguilla,
AL: CountryCode.Albania,
AM: CountryCode.Armenia,
AO: CountryCode.Angola,
AQ: CountryCode.Antarctica,
AR: CountryCode.Argentina,
AS: CountryCode['American Samoa'],
AT: CountryCode.Austria,
AU: CountryCode.Australia,
AW: CountryCode.Aruba,
AX: CountryCode['Åland Islands'],
AZ: CountryCode.Azerbaijan,
BA: CountryCode['Bosnia and Herzegovina'],
BB: CountryCode.Barbados,
BD: CountryCode.Bangladesh,
BE: CountryCode.Belgium,
BF: CountryCode['Burkina Faso'],
BG: CountryCode.Bulgaria,
BH: CountryCode.Bahrain,
BI: CountryCode.Burundi,
BJ: CountryCode.Benin,
BL: CountryCode['Saint Barthélemy'],
BM: CountryCode.Bermuda,
BN: CountryCode['Brunei Darussalam'],
BO: CountryCode['Bolivia (Plurinational State of)'],
BQ: CountryCode['Bonaire, Sint Eustatius and Saba'],
BR: CountryCode.Brazil,
BS: CountryCode['Bahamas (the)'],
BT: CountryCode.Bhutan,
BV: CountryCode['Bouvet Island'],
BW: CountryCode.Botswana,
BY: CountryCode.Belarus,
BZ: CountryCode.Belize,
CA: CountryCode.Canada,
CC: CountryCode['Cocos (Keeling) Islands (the)'],
CD: CountryCode['Congo (the Democratic Republic of the)'],
CF: CountryCode['Central African Republic (the)'],
CG: CountryCode['Congo (the)'],
CH: CountryCode.Switzerland,
CI: CountryCode["Côte d'Ivoire"],
CK: CountryCode['Cook Islands (the)'],
CL: CountryCode.Chile,
CM: CountryCode.Cameroon,
CN: CountryCode.China,
CO: CountryCode.Colombia,
CR: CountryCode['Costa Rica'],
CU: CountryCode.Cuba,
CV: CountryCode['Cabo Verde'],
CW: CountryCode.Curaçao,
CX: CountryCode['Christmas Island'],
CY: CountryCode.Cyprus,
CZ: CountryCode.Czechia,
DE: CountryCode.Germany,
DJ: CountryCode.Djibouti,
DK: CountryCode.Denmark,
DM: CountryCode.Dominica,
DO: CountryCode['Dominican Republic (the)'],
DZ: CountryCode.Algeria,
EC: CountryCode.Ecuador,
EE: CountryCode.Estonia,
EG: CountryCode.Egypt,
EH: CountryCode['Western Sahara'],
ER: CountryCode.Eritrea,
ES: CountryCode.Spain,
ET: CountryCode.Ethiopia,
FI: CountryCode.Finland,
FJ: CountryCode.Fiji,
FK: CountryCode['Falkland Islands (the) [Malvinas]'],
FM: CountryCode['Micronesia (Federated States of)'],
FO: CountryCode['Faroe Islands (the)'],
FR: CountryCode.France,
GA: CountryCode.Gabon,
GB: CountryCode['United Kingdom of Great Britain and Northern Ireland (the)'],
GD: CountryCode.Grenada,
GE: CountryCode.Georgia,
GF: CountryCode['French Guiana'],
GG: CountryCode.Guernsey,
GH: CountryCode.Ghana,
GI: CountryCode.Gibraltar,
GL: CountryCode.Greenland,
GM: CountryCode['Gambia (the)'],
GN: CountryCode.Guinea,
GP: CountryCode.Guadeloupe,
GQ: CountryCode['Equatorial Guinea'],
GR: CountryCode.Greece,
GS: CountryCode['South Georgia and the South Sandwich Islands'],
GT: CountryCode.Guatemala,
GU: CountryCode.Guam,
GW: CountryCode['Guinea-Bissau'],
GY: CountryCode.Guyana,
HK: CountryCode['Hong Kong'],
HM: CountryCode['Heard Island and McDonald Islands'],
HN: CountryCode.Honduras,
HR: CountryCode.Croatia,
HT: CountryCode.Haiti,
HU: CountryCode.Hungary,
ID: CountryCode.Indonesia,
IE: CountryCode.Ireland,
IL: CountryCode.Israel,
IM: CountryCode['Isle of Man'],
IN: CountryCode.India,
IO: CountryCode['British Indian Ocean Territory (the)'],
IQ: CountryCode.Iraq,
IR: CountryCode['Iran (Islamic Republic of)'],
IS: CountryCode.Iceland,
IT: CountryCode.Italy,
JE: CountryCode.Jersey,
JM: CountryCode.Jamaica,
JO: CountryCode.Jordan,
JP: CountryCode.Japan,
KE: CountryCode.Kenya,
KG: CountryCode.Kyrgyzstan,
KH: CountryCode.Cambodia,
KI: CountryCode.Kiribati,
KM: CountryCode['Comoros (the)'],
KN: CountryCode['Saint Kitts and Nevis'],
KP: CountryCode["Korea (the Democratic People's Republic of)"],
KR: CountryCode['Korea (the Republic of)'],
KW: CountryCode.Kuwait,
KY: CountryCode['Cayman Islands (the)'],
KZ: CountryCode.Kazakhstan,
LA: CountryCode["Lao People's Democratic Republic (the)"],
LB: CountryCode.Lebanon,
LC: CountryCode['Saint Lucia'],
LI: CountryCode.Liechtenstein,
LK: CountryCode['Sri Lanka'],
LR: CountryCode.Liberia,
LS: CountryCode.Lesotho,
LT: CountryCode.Lithuania,
LU: CountryCode.Luxembourg,
LV: CountryCode.Latvia,
LY: CountryCode.Libya,
MA: CountryCode.Morocco,
MC: CountryCode.Monaco,
MD: CountryCode['Moldova (the Republic of)'],
ME: CountryCode.Montenegro,
MF: CountryCode['Saint Martin (French part)'],
MG: CountryCode.Madagascar,
MH: CountryCode['Marshall Islands (the)'],
MK: CountryCode['Republic of North Macedonia'],
ML: CountryCode.Mali,
MM: CountryCode.Myanmar,
MN: CountryCode.Mongolia,
MO: CountryCode.Macao,
MP: CountryCode['Northern Mariana Islands (the)'],
MQ: CountryCode.Martinique,
MR: CountryCode.Mauritania,
MS: CountryCode.Montserrat,
MT: CountryCode.Malta,
MU: CountryCode.Mauritius,
MV: CountryCode.Maldives,
MW: CountryCode.Malawi,
MX: CountryCode.Mexico,
MY: CountryCode.Malaysia,
MZ: CountryCode.Mozambique,
NA: CountryCode.Namibia,
NC: CountryCode['New Caledonia'],
NE: CountryCode['Niger (the)'],
NF: CountryCode['Norfolk Island'],
NG: CountryCode.Nigeria,
NI: CountryCode.Nicaragua,
NL: CountryCode['Netherlands (the)'],
NO: CountryCode.Norway,
NP: CountryCode.Nepal,
NR: CountryCode.Nauru,
NU: CountryCode.Niue,
NZ: CountryCode['New Zealand'],
OM: CountryCode.Oman,
PA: CountryCode.Panama,
PE: CountryCode.Peru,
PF: CountryCode['French Polynesia'],
PG: CountryCode['Papua New Guinea'],
PH: CountryCode['Philippines (the)'],
PK: CountryCode.Pakistan,
PL: CountryCode.Poland,
PM: CountryCode['Saint Pierre and Miquelon'],
PN: CountryCode.Pitcairn,
PR: CountryCode['Puerto Rico'],
PS: CountryCode['Palestine, State of'],
PT: CountryCode.Portugal,
PW: CountryCode.Palau,
PY: CountryCode.Paraguay,
QA: CountryCode.Qatar,
RE: CountryCode.Réunion,
RO: CountryCode.Romania,
RS: CountryCode.Serbia,
RU: CountryCode['Russian Federation (the)'],
RW: CountryCode.Rwanda,
SA: CountryCode['Saudi Arabia'],
SB: CountryCode['Solomon Islands'],
SC: CountryCode.Seychelles,
SD: CountryCode['Sudan (the)'],
SE: CountryCode.Sweden,
SG: CountryCode.Singapore,
SH: CountryCode['Saint Helena, Ascension and Tristan da Cunha'],
SI: CountryCode.Slovenia,
SJ: CountryCode['Svalbard and Jan Mayen'],
SK: CountryCode.Slovakia,
SL: CountryCode['Sierra Leone'],
SM: CountryCode['San Marino'],
SN: CountryCode.Senegal,
SO: CountryCode.Somalia,
SR: CountryCode.Suriname,
SS: CountryCode['South Sudan'],
ST: CountryCode['Sao Tome and Principe'],
SV: CountryCode['El Salvador'],
SX: CountryCode['Sint Maarten (Dutch part)'],
SY: CountryCode['Syrian Arab Republic'],
SZ: CountryCode.Eswatini,
TC: CountryCode['Turks and Caicos Islands (the)'],
TD: CountryCode.Chad,
TF: CountryCode['French Southern Territories (the)'],
TG: CountryCode.Togo,
TH: CountryCode.Thailand,
TJ: CountryCode.Tajikistan,
TK: CountryCode.Tokelau,
TL: CountryCode['Timor-Leste'],
TM: CountryCode.Turkmenistan,
TN: CountryCode.Tunisia,
TO: CountryCode.Tonga,
TR: CountryCode.Turkey,
TT: CountryCode['Trinidad and Tobago'],
TV: CountryCode.Tuvalu,
TW: CountryCode['Taiwan (Province of China)'],
TZ: CountryCode['Tanzania, United Republic of'],
UA: CountryCode.Ukraine,
UG: CountryCode.Uganda,
UM: CountryCode['United States Minor Outlying Islands (the)'],
US: CountryCode['United States of America (the)'],
UY: CountryCode.Uruguay,
UZ: CountryCode.Uzbekistan,
VA: CountryCode['Holy See (the)'],
VC: CountryCode['Saint Vincent and the Grenadines'],
VE: CountryCode['Venezuela (Bolivarian Republic of)'],
VG: CountryCode['Virgin Islands (British)'],
VI: CountryCode['Virgin Islands (U.S.)'],
VN: CountryCode['Viet Nam'],
VU: CountryCode.Vanuatu,
WF: CountryCode['Wallis and Futuna'],
WS: CountryCode.Samoa,
YE: CountryCode.Yemen,
YT: CountryCode.Mayotte,
ZA: CountryCode['South Africa'],
ZM: CountryCode.Zambia,
ZW: CountryCode.Zimbabwe,
};
if (country === 'XK') {
// TODO: remove this once green invoice adds Kosovo to their list
return CountryCode.Serbia;
}
const code = greenInvoiceToCountryCodeMap[country];
if (code) {
return code;
}
throw new Error(`Unsupported Green Invoice country: ${country}`);
}
export function countryCodeToGreenInvoiceCountry(countryCode) {
const countryCodeToGreenInvoiceMap = {
[CountryCode.Afghanistan]: 'AF',
[CountryCode['Åland Islands']]: 'AX',
[CountryCode.Albania]: 'AL',
[CountryCode.Algeria]: 'DZ',
[CountryCode['American Samoa']]: 'AS',
[CountryCode.Andorra]: 'AD',
[CountryCode.Angola]: 'AO',
[CountryCode.Anguilla]: 'AI',
[CountryCode.Antarctica]: 'AQ',
[CountryCode['Antigua and Barbuda']]: 'AG',
[CountryCode.Argentina]: 'AR',
[CountryCode.Armenia]: 'AM',
[CountryCode.Aruba]: 'AW',
[CountryCode.Australia]: 'AU',
[CountryCode.Austria]: 'AT',
[CountryCode.Azerbaijan]: 'AZ',
[CountryCode['Bahamas (the)']]: 'BS',
[CountryCode.Bahrain]: 'BH',
[CountryCode.Bangladesh]: 'BD',
[CountryCode.Barbados]: 'BB',
[CountryCode.Belarus]: 'BY',
[CountryCode.Belgium]: 'BE',
[CountryCode.Belize]: 'BZ',
[CountryCode.Benin]: 'BJ',
[CountryCode.Bermuda]: 'BM',
[CountryCode.Bhutan]: 'BT',
[CountryCode['Bolivia (Plurinational State of)']]: 'BO',
[CountryCode['Bonaire, Sint Eustatius and Saba']]: 'BQ',
[CountryCode['Bosnia and Herzegovina']]: 'BA',
[CountryCode.Botswana]: 'BW',
[CountryCode['Bouvet Island']]: 'BV',
[CountryCode.Brazil]: 'BR',
[CountryCode['British Indian Ocean Territory (the)']]: 'IO',
[CountryCode['Brunei Darussalam']]: 'BN',
[CountryCode.Bulgaria]: 'BG',
[CountryCode['Burkina Faso']]: 'BF',
[CountryCode.Burundi]: 'BI',
[CountryCode['Cabo Verde']]: 'CV',
[CountryCode.Cambodia]: 'KH',
[CountryCode.Cameroon]: 'CM',
[CountryCode.Canada]: 'CA',
[CountryCode['Cayman Islands (the)']]: 'KY',
[CountryCode['Central African Republic (the)']]: 'CF',
[CountryCode.Chad]: 'TD',
[CountryCode.Chile]: 'CL',
[CountryCode.China]: 'CN',
[CountryCode['Christmas Island']]: 'CX',
[CountryCode['Cocos (Keeling) Islands (the)']]: 'CC',
[CountryCode.Colombia]: 'CO',
[CountryCode['Comoros (the)']]: 'KM',
[CountryCode['Congo (the Democratic Republic of the)']]: 'CD',
[CountryCode['Congo (the)']]: 'CG',
[CountryCode['Cook Islands (the)']]: 'CK',
[CountryCode['Costa Rica']]: 'CR',
[CountryCode.Croatia]: 'HR',
[CountryCode.Cuba]: 'CU',
[CountryCode.Curaçao]: 'CW',
[CountryCode.Cyprus]: 'CY',
[CountryCode.Czechia]: 'CZ',
[CountryCode["Côte d'Ivoire"]]: 'CI',
[CountryCode.Denmark]: 'DK',
[CountryCode.Djibouti]: 'DJ',
[CountryCode.Dominica]: 'DM',
[CountryCode['Dominican Republic (the)']]: 'DO',
[CountryCode.Ecuador]: 'EC',
[CountryCode.Egypt]: 'EG',
[CountryCode['El Salvador']]: 'SV',
[CountryCode['Equatorial Guinea']]: 'GQ',
[CountryCode.Eritrea]: 'ER',
[CountryCode.Estonia]: 'EE',
[CountryCode.Eswatini]: 'SZ',
[CountryCode.Ethiopia]: 'ET',
[CountryCode['Falkland Islands (the) [Malvinas]']]: 'FK',
[CountryCode['Faroe Islands (the)']]: 'FO',
[CountryCode.Fiji]: 'FJ',
[CountryCode.Finland]: 'FI',
[CountryCode.France]: 'FR',
[CountryCode['French Guiana']]: 'GF',
[CountryCode['French Polynesia']]: 'PF',
[CountryCode['French Southern Territories (the)']]: 'TF',
[CountryCode.Gabon]: 'GA',
[CountryCode['Gambia (the)']]: 'GM',
[CountryCode.Georgia]: 'GE',
[CountryCode.Germany]: 'DE',
[CountryCode.Ghana]: 'GH',
[CountryCode.Gibraltar]: 'GI',
[CountryCode.Greece]: 'GR',
[CountryCode.Greenland]: 'GL',
[CountryCode.Grenada]: 'GD',
[CountryCode.Guadeloupe]: 'GP',
[CountryCode.Guam]: 'GU',
[CountryCode.Guatemala]: 'GT',
[CountryCode.Guernsey]: 'GG',
[CountryCode.Guinea]: 'GN',
[CountryCode['Guinea-Bissau']]: 'GW',
[CountryCode.Guyana]: 'GY',
[CountryCode.Haiti]: 'HT',
[CountryCode['Heard Island and McDonald Islands']]: 'HM',
[CountryCode['Holy See (the)']]: 'VA',
[CountryCode.Honduras]: 'HN',
[CountryCode['Hong Kong']]: 'HK',
[CountryCode.Hungary]: 'HU',
[CountryCode.Iceland]: 'IS',
[CountryCode.India]: 'IN',
[CountryCode.Indonesia]: 'ID',
[CountryCode['Iran (Islamic Republic of)']]: 'IR',
[CountryCode.Iraq]: 'IQ',
[CountryCode.Ireland]: 'IE',
[CountryCode['Isle of Man']]: 'IM',
[CountryCode.Israel]: 'IL',
[CountryCode.Italy]: 'IT',
[CountryCode.Jamaica]: 'JM',
[CountryCode.Japan]: 'JP',
[CountryCode.Jersey]: 'JE',
[CountryCode.Jordan]: 'JO',
[CountryCode.Kazakhstan]: 'KZ',
[CountryCode.Kenya]: 'KE',
[CountryCode.Kiribati]: 'KI',
[CountryCode["Korea (the Democratic People's Republic of)"]]: 'KP',
[CountryCode['Korea (the Republic of)']]: 'KR',
[CountryCode.Kuwait]: 'KW',
[CountryCode.Kyrgyzstan]: 'KG',
[CountryCode["Lao People's Democratic Republic (the)"]]: 'LA',
[CountryCode.Latvia]: 'LV',
[CountryCode.Lebanon]: 'LB',
[CountryCode.Lesotho]: 'LS',
[CountryCode.Liberia]: 'LR',
[CountryCode.Libya]: 'LY',
[CountryCode.Liechtenstein]: 'LI',
[CountryCode.Lithuania]: 'LT',
[CountryCode.Luxembourg]: 'LU',
[CountryCode.Macao]: 'MO',
[CountryCode.Madagascar]: 'MG',
[CountryCode.Malawi]: 'MW',
[CountryCode.Malaysia]: 'MY',
[CountryCode.Maldives]: 'MV',
[CountryCode.Mali]: 'ML',
[CountryCode.Malta]: 'MT',
[CountryCode['Marshall Islands (the)']]: 'MH',
[CountryCode.Martinique]: 'MQ',
[CountryCode.Mauritania]: 'MR',
[CountryCode.Mauritius]: 'MU',
[CountryCode.Mayotte]: 'YT',
[CountryCode.Mexico]: 'MX',
[CountryCode['Micronesia (Federated States of)']]: 'FM',
[CountryCode['Moldova (the Republic of)']]: 'MD',
[CountryCode.Monaco]: 'MC',
[CountryCode.Mongolia]: 'MN',
[CountryCode.Montenegro]: 'ME',
[CountryCode.Montserrat]: 'MS',
[CountryCode.Morocco]: 'MA',
[CountryCode.Mozambique]: 'MZ',
[CountryCode.Myanmar]: 'MM',
[CountryCode.Namibia]: 'NA',
[CountryCode.Nauru]: 'NR',
[CountryCode.Nepal]: 'NP',
[CountryCode['Netherlands (the)']]: 'NL',
[CountryCode['New Caledonia']]: 'NC',
[CountryCode['New Zealand']]: 'NZ',
[CountryCode.Nicaragua]: 'NI',
[CountryCode['Niger (the)']]: 'NE',
[CountryCode.Nigeria]: 'NG',
[CountryCode.Niue]: 'NU',
[CountryCode['Norfolk Island']]: 'NF',
[CountryCode['Northern Mariana Islands (the)']]: 'MP',
[CountryCode.Norway]: 'NO',
[CountryCode.Oman]: 'OM',
[CountryCode.Pakistan]: 'PK',
[CountryCode.Palau]: 'PW',
[CountryCode['Palestine, State of']]: 'PS',
[CountryCode.Panama]: 'PA',
[CountryCode['Papua New Guinea']]: 'PG',
[CountryCode.Paraguay]: 'PY',
[CountryCode.Peru]: 'PE',
[CountryCode['Philippines (the)']]: 'PH',
[CountryCode.Pitcairn]: 'PN',
[CountryCode.Poland]: 'PL',
[CountryCode.Portugal]: 'PT',
[CountryCode['Puerto Rico']]: 'PR',
[CountryCode.Qatar]: 'QA',
[CountryCode['Republic of North Macedonia']]: 'MK',
[CountryCode.Romania]: 'RO',
[CountryCode['Russian Federation (the)']]: 'RU',
[CountryCode.Rwanda]: 'RW',
[CountryCode.Réunion]: 'RE',
[CountryCode['Saint Barthélemy']]: 'BL',
[CountryCode['Saint Helena, Ascension and Tristan da Cunha']]: 'SH',
[CountryCode['Saint Kitts and Nevis']]: 'KN',
[CountryCode['Saint Lucia']]: 'LC',
[CountryCode['Saint Martin (French part)']]: 'MF',
[CountryCode['Saint Pierre and Miquelon']]: 'PM',
[CountryCode['Saint Vincent and the Grenadines']]: 'VC',
[CountryCode.Samoa]: 'WS',
[CountryCode['San Marino']]: 'SM',
[CountryCode['Sao Tome and Principe']]: 'ST',
[CountryCode['Saudi Arabia']]: 'SA',
[CountryCode.Senegal]: 'SN',
[CountryCode.Serbia]: 'RS',
[CountryCode.Seychelles]: 'SC',
[CountryCode['Sierra Leone']]: 'SL',
[CountryCode.Singapore]: 'SG',
[CountryCode['Sint Maarten (Dutch part)']]: 'SX',
[CountryCode.Slovakia]: 'SK',
[CountryCode.Slovenia]: 'SI',
[CountryCode['Solomon Islands']]: 'SB',
[CountryCode.Somalia]: 'SO',
[CountryCode['South Africa']]: 'ZA',
[CountryCode['South Georgia and the South Sandwich Islands']]: 'GS',
[CountryCode['South Sudan']]: 'SS',
[CountryCode.Spain]: 'ES',
[CountryCode['Sri Lanka']]: 'LK',
[CountryCode['Sudan (the)']]: 'SD',
[CountryCode.Suriname]: 'SR',
[CountryCode['Svalbard and Jan Mayen']]: 'SJ',
[CountryCode.Sweden]: 'SE',
[CountryCode.Switzerland]: 'CH',
[CountryCode['Syrian Arab Republic']]: 'SY',
[CountryCode['Taiwan (Province of China)']]: 'TW',
[CountryCode.Tajikistan]: 'TJ',
[CountryCode['Tanzania, United Republic of']]: 'TZ',
[CountryCode.Thailand]: 'TH',
[CountryCode['Timor-Leste']]: 'TL',
[CountryCode.Togo]: 'TG',
[CountryCode.Tokelau]: 'TK',
[CountryCode.Tonga]: 'TO',
[CountryCode['Trinidad and Tobago']]: 'TT',
[CountryCode.Tunisia]: 'TN',
[CountryCode.Turkey]: 'TR',
[CountryCode.Turkmenistan]: 'TM',
[CountryCode['Turks and Caicos Islands (the)']]: 'TC',
[CountryCode.Tuvalu]: 'TV',
[CountryCode.Uganda]: 'UG',
[CountryCode.Ukraine]: 'UA',
[CountryCode['United Arab Emirates (the)']]: 'AE',
[CountryCode['United Kingdom of Great Britain and Northern Ireland (the)']]: 'GB',
[CountryCode['United States Minor Outlying Islands (the)']]: 'UM',
[CountryCode['United States of America (the)']]: 'US',
[CountryCode.Uruguay]: 'UY',
[CountryCode.Uzbekistan]: 'UZ',
[CountryCode.Vanuatu]: 'VU',
[CountryCode['Venezuela (Bolivarian Republic of)']]: 'VE',
[CountryCode['Viet Nam']]: 'VN',
[CountryCode['Virgin Islands (British)']]: 'VG',
[CountryCode['Virgin Islands (U.S.)']]: 'VI',
[CountryCode['Wallis and Futuna']]: 'WF',
[CountryCode['Western Sahara']]: 'EH',
[CountryCode.Yemen]: 'YE',
[CountryCode.Zambia]: 'ZM',
[CountryCode.Zimbabwe]: 'ZW',
};
const greenInvoiceCountry = countryCodeToGreenInvoiceMap[countryCode];
if (greenInvoiceCountry) {
return greenInvoiceCountry;
}
throw new Error(`Unsupported country code: ${countryCode}`);
}
export function greenInvoiceToDocumentStatus(greenInvoiceStatus) {
switch (greenInvoiceStatus) {
case 0:
return 'OPEN';
case 1:
return 'CLOSED';
case 2:
return 'MANUALLY_CLOSED';
case 3:
return 'CANCELLED_BY_OTHER_DOC';
case 4:
return 'CANCELLED';
default:
throw new Error(`Unsupported Green Invoice document status: ${greenInvoiceStatus}`);
}
}
export async function getLinkedDocuments(injector, externalDocumentId) {
const greenInvoiceDocument = await injector
.get(GreenInvoiceClientProvider)
.documentLoader.load(externalDocumentId);
if (!greenInvoiceDocument?.linkedDocuments) {
return null;
}
const linkedDocuments = greenInvoiceDocument.linkedDocuments.filter(Boolean);
if (!linkedDocuments.length) {
return null;
}
const linkedDocumentsIds = [];
await Promise.all(linkedDocuments.map(async (linkedDocument) => {
const issuedDocument = await injector
.get(IssuedDocumentsProvider)
.getIssuedDocumentsByExternalIdLoader.load(linkedDocument.id);
if (!issuedDocument?.id) {
throw new GraphQLError(`Linked document with ID ${linkedDocument.id} not found in issued documents`);
}
linkedDocumentsIds.push(issuedDocument.id);
}));
return linkedDocumentsIds;
}
export async function insertNewDocumentFromGreenInvoice(injector, greenInvoiceDoc, ownerId, preDictatedChargeId) {
const documentType = normalizeGreenInvoiceDocumentType(greenInvoiceDoc.type);
const isOwnerCreditor = greenInvoiceDoc.amount > 0 && documentType !== DocumentType.CreditInvoice;
const links = await injector.get(GreenInvoiceClientProvider).getDocumentLinks(greenInvoiceDoc.id);
if (!links) {
throw new GraphQLError(`No links found for Green Invoice document ID: ${greenInvoiceDoc.id}`);
}
const fileUrl = links.en ?? links.origin;
try {
// generate preview image via cloudinary
const imagePromise = injector.get(CloudinaryProvider).uploadInvoiceToCloudinary(fileUrl);
// Get matching business
const clientPromise = greenInvoiceDoc.client.id
? injector
.get(ClientsProvider)
.getClientByGreenInvoiceIdLoader.load(greenInvoiceDoc.client.id)
: Promise.resolve(null);
const linkedDocumentsPromise = getLinkedDocuments(injector, greenInvoiceDoc.id);
const fileHashPromise = async () => {
try {
// Before creating rawDocument
const fileResponse = await fetch(fileUrl);
if (!fileResponse.ok) {
// Handle error, maybe log and continue with null hash
throw new Error(`Failed to fetch file from GreenInvoice: ${fileUrl}`);
}
const fileContent = await fileResponse.text();
const fileHash = hashStringToInt(fileContent).toString();
return fileHash;
}
catch (error) {
console.error('Error fetching file for hash calculation:', error);
return null;
}
};
const [{ imageUrl }, client, linkedDocumentIds, fileHash] = await Promise.all([
imagePromise,
clientPromise,
linkedDocumentsPromise,
fileHashPromise(),
]);
let chargeId = preDictatedChargeId || null;
// if linked documents exist, use the first one to get the charge ID
if (!chargeId && linkedDocumentIds?.length) {
const linkedDocId = linkedDocumentIds[0];
const document = await injector
.get(DocumentsProvider)
.getDocumentsByIdLoader.load(linkedDocId);
if (document?.charge_id) {
chargeId = document.charge_id;
}
}
let charge = undefined;
if (chargeId) {
charge = await injector.get(ChargesProvider).getChargeByIdLoader.load(chargeId);
if (!charge) {
throw new Error(`Charge with ID ${chargeId} not found`);
}
}
else {
// Generate new parent charge
let userDescription = 'Green Invoice generated charge';
const income = greenInvoiceDoc.income;
if (income && income.length > 0 && income[0].description && income[0].description !== '') {
userDescription = income
.filter(item => item?.description)
.map(item => item.description)
.join(', ');
}
else if (greenInvoiceDoc.description && greenInvoiceDoc.description !== '') {
userDescription = greenInvoiceDoc.description;
}
charge = await injector.get(ChargesProvider).generateCharge({
ownerId,
userDescription,
type: 'COMMON',
});
if (!charge) {
throw new Error('Failed to generate charge');
}
chargeId = charge.id;
}
const counterpartyId = client?.business_id ?? null;
// insert document
const rawDocument = {
ownerId: charge.owner_id,
image: imageUrl,
file: fileUrl,
documentType,
serialNumber: greenInvoiceDoc.number,
date: greenInvoiceDoc.documentDate,
amount: greenInvoiceDoc.amount,
currencyCode: formatCurrency(greenInvoiceDoc.currency),
vat: greenInvoiceDoc.vat,
chargeId,
vatReportDateOverride: null,
noVatAmount: null,
creditorId: isOwnerCreditor ? ownerId : counterpartyId,
debtorId: isOwnerCreditor ? counterpartyId : ownerId,
allocationNumber: null, // TODO: add allocation number from GreenInvoice API
exchangeRateOverride: null,
fileHash,
remarks: greenInvoiceDoc.remarks || null,
description: greenInvoiceDoc.description || null,
};
const newDocumentResponse = await injector
.get(DocumentsProvider)
.insertDocuments({ documents: [rawDocument] });
if (!newDocumentResponse || newDocumentResponse.length === 0) {
throw new Error('Failed to insert document');
}
const newDocument = newDocumentResponse[0];
// insert issued document
await injector
.get(IssuedDocumentsProvider)
.insertIssuedDocuments({
issuedDocuments: [
{
ownerId: newDocument.owner_id,
externalId: greenInvoiceDoc.id,
id: newDocument.id,
status: greenInvoiceToDocumentStatus(greenInvoiceDoc.status),
linkedDocumentIds,
},
],
})
.catch(e => {
console.error('Failed to insert issued document', e);
throw new GraphQLError(`Failed to insert issued document for Green Invoice ID: ${greenInvoiceDoc.id}`);
});
return newDocument;
}
catch (e) {
throw new GraphQLError(`Error adding Green Invoice document: ${e}\n\n${JSON.stringify(greenInvoiceDoc, null, 2)}`);
}
}
export async function getGreenInvoiceDocuments(injector, recursive = false) {
const documents = [];
async function getDocuments(page = 1) {
const data = await injector.get(GreenInvoiceClientProvider).searchDocuments({
input: { pageSize: 100, sort: 'creationDate', page },
});
if (!data?.items) {
if (!recursive) {
throw new GraphQLError('Failed to fetch documents');
}
return;
}
documents.push(...data.items.filter(item => item !== null));
if (data.items.length < 100) {
return;
}
if (recursive) {
await getDocuments(page + 1);
}
}
await getDocuments();
return documents;
}
export async function convertDocumentInputIntoGreenInvoiceInput(initialInput, injector) {
let client = undefined;
if (initialInput.client) {
const clientInfo = await injector
.get(ClientsProvider)
.getClientByIdLoader.load(initialInput.client.id);
if (!clientInfo) {
throw new GraphQLError(`Client with business ID ${initialInput.client.id} not found`);
}
let greenInvoiceId;
try {
greenInvoiceId =
validateClientIntegrations(clientInfo.integrations ?? {}).greenInvoiceId ?? null;
}
catch (error) {
console.error('Failed to validate client integrations', error);
throw new GraphQLError(`Client with business ID ${initialInput.client.id} has invalid integrations`);
}
if (!greenInvoiceId) {
throw new GraphQLError(`Client with business ID ${initialInput.client.id} not found in Green Invoice`);
}
const greenInvoiceClient = await injector
.get(GreenInvoiceClientProvider)
.clientLoader.load(greenInvoiceId);
if (!greenInvoiceClient) {
throw new GraphQLError(`Green Invoice client with ID ${greenInvoiceId} not found`);
}
const emails = ['ap@the-guild.dev']; // TODO: remove hardcoded email
const inputEmails = initialInput.client?.emails?.filter(Boolean) ?? [];
if (inputEmails.length) {
emails.push(...inputEmails);
}
else {
emails.push(...(greenInvoiceClient.emails ?? []));
}
client = {
id: greenInvoiceClient.id,
country: countryCodeToGreenInvoiceCountry(initialInput.client.country),
name: initialInput.client.name,
phone: initialInput.client.phone,
taxId: initialInput.client.taxId,
self: false,
address: initialInput.client.address,
city: initialInput.client.city,
zip: initialInput.client.zipCode,
fax: initialInput.client.fax,
mobile: initialInput.client.mobile,
emails,
};
}
// clean input by converting to writeable and removing unwanted properties
const cleanedInput = { ...initialInput };
delete cleanedInput.language;
const input = {
...cleanedInput,
currency: convertCurrencyToGreenInvoice(initialInput.currency),
type: getGreenInvoiceDocumentType(initialInput.type),
lang: getGreenInvoiceDocumentLanguage(initialInput.language),
vatType: getGreenInvoiceDocumentVatType(initialInput.vatType ?? 'DEFAULT'),
discount: initialInput.discount
? {
...initialInput.discount,
type: getGreenInvoiceDocumentDiscountType(initialInput.discount.type),
}
: undefined,
client,
income: initialInput.income?.map(income => ({
...income,
currency: convertCurrencyToGreenInvoice(income.currency),
vatType: getGreenInvoiceDocumentVatType(income.vatType ?? 'DEFAULT'),
})) ?? [],
payment: initialInput.payment?.map(payment => ({
...payment,
type: getGreenInvoiceDocumentPaymentType(payment.type),
subType: undefined,
appType: undefined,
cardType: payment.cardType
? getGreenInvoiceDocumentPaymentCardType(payment.cardType)
: undefined,
dealType: undefined,
currency: convertCurrencyToGreenInvoice(payment.currency),
})),
linkedDocumentIds: initialInput.linkedDocumentIds?.length
? [...initialInput.linkedDocumentIds]
: undefined,
linkType: initialInput.linkType
? getGreenInvoiceDocumentLinkType(initialInput.linkType)
: undefined,
};
return input;
}
export async function convertGreenInvoiceDocumentToDocumentDraft(greenInvoiceDocument, injector) {
const client = await (greenInvoiceDocument.client?.id
? injector
.get(ClientsProvider)
.getClientByGreenInvoiceIdLoader.load(greenInvoiceDocument.client?.id)
: Promise.resolve(undefined));
return {
...greenInvoiceDocument,
client,
currency: greenInvoiceDocument.currency,
income: greenInvoiceDocument.income?.filter(Boolean).map(income => ({
...income,
currency: income.currency,
vatType: getVatTypeFromGreenInvoiceDocument(income.vatType),
})),
language: getLanguageFromGreenInvoiceDocument(greenInvoiceDocument.lang),
payment: greenInvoiceDocument.payment?.filter(Boolean).map(payment => ({
...payment,
appType: undefined,
cardType: payment?.cardType
? getCardTypeFromGreenInvoiceDocumentPayment(payment.cardType)
: undefined,
currency: payment.currency,
dealType: undefined,
subType: undefined,
type: getTypeFromGreenInvoiceDocumentPayment(payment.type),
})),
type: getTypeFromGreenInvoiceDocument(greenInvoiceDocument.type),
vatType: getVatTypeFromGreenInvoiceDocument(greenInvoiceDocument.vatType),
};
}
//# sourceMappingURL=green-invoice.helper.js.map