@marteye/studiojs 1.1.2 → 1.1.4

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/dist/index.esm.js CHANGED
@@ -179,6 +179,12 @@ function create(_) {
179
179
  */
180
180
  constructEvent: async (bodyAsBuffer, signature, endpointSecret) => {
181
181
  let rawBody = bodyAsBuffer.toString();
182
+ if (!endpointSecret) {
183
+ throw new Error("Endpoint secret is required");
184
+ }
185
+ if (!signature) {
186
+ throw new Error("Signature is required");
187
+ }
182
188
  let expectedSignature = createHmac("sha256", endpointSecret)
183
189
  .update(rawBody)
184
190
  .digest("hex");
@@ -210,14 +216,61 @@ function resources(httpClient) {
210
216
 
211
217
  const BaseUrl = "https://www.marteyestudio.com/api";
212
218
  const DefaultTimeout = 10000;
213
- function Studio(apiKey, baseUrl = BaseUrl, defaultTimeout = DefaultTimeout, debug = false) {
214
- let httpClient = SimpleHttpClient(baseUrl, apiKey, getFetch(), defaultTimeout, debug);
219
+ function Studio(info) {
220
+ var _a, _b, _c, _d;
221
+ let apiKeyOrNull = (_a = info.apiKey) !== null && _a !== void 0 ? _a : process.env.STUDIO_API_KEY;
222
+ if (!apiKeyOrNull) {
223
+ throw new Error("Studio API key is not set");
224
+ }
225
+ let infoWithDefaults = {
226
+ apiKey: apiKeyOrNull,
227
+ baseUrl: (_b = info.baseUrl) !== null && _b !== void 0 ? _b : BaseUrl,
228
+ defaultTimeout: (_c = info.defaultTimeout) !== null && _c !== void 0 ? _c : DefaultTimeout,
229
+ debug: (_d = info.debug) !== null && _d !== void 0 ? _d : false,
230
+ };
231
+ let httpClient = SimpleHttpClient(infoWithDefaults.baseUrl, infoWithDefaults.apiKey, getFetch(), infoWithDefaults.defaultTimeout, infoWithDefaults.debug);
215
232
  return {
216
233
  ...resources(httpClient),
217
- isDebugMode: debug,
234
+ isDebugMode: infoWithDefaults.debug,
218
235
  };
219
236
  }
220
237
 
238
+ const SupportedSuperTypes = [
239
+ "Sheep",
240
+ "Goats",
241
+ "Cattle",
242
+ "Pigs",
243
+ "Horses",
244
+ "Deer",
245
+ "Poultry",
246
+ "Machinery",
247
+ "Antiques",
248
+ "Other",
249
+ ];
250
+ const LivestockSuperTypes = [
251
+ "Sheep",
252
+ "Goats",
253
+ "Cattle",
254
+ "Pigs",
255
+ "Horses",
256
+ "Deer",
257
+ "Poultry",
258
+ ];
259
+ const SupportedCurrencyCodes = ["GBP", "EUR", "USD"];
260
+ const SupportedUnitsOfSale = [
261
+ "Per KG",
262
+ "Per Item",
263
+ "Per Lot",
264
+ "Per 1000KG",
265
+ ];
266
+ const SupportedPaymentMethods = [
267
+ "BACS",
268
+ "Cheque",
269
+ "BankTransfer",
270
+ "Cash",
271
+ "Card",
272
+ "Credit",
273
+ ];
221
274
  const supportedWebhookEvents = [
222
275
  "market.updated",
223
276
  "sale.created",
@@ -247,6 +300,16 @@ const supportedWebhookEvents = [
247
300
  "member.deleted",
248
301
  ];
249
302
 
303
+ var types = /*#__PURE__*/Object.freeze({
304
+ __proto__: null,
305
+ LivestockSuperTypes: LivestockSuperTypes,
306
+ SupportedCurrencyCodes: SupportedCurrencyCodes,
307
+ SupportedPaymentMethods: SupportedPaymentMethods,
308
+ SupportedSuperTypes: SupportedSuperTypes,
309
+ SupportedUnitsOfSale: SupportedUnitsOfSale,
310
+ supportedWebhookEvents: supportedWebhookEvents
311
+ });
312
+
250
313
  /**
251
314
  * Headers used by Studio to identify webhook and action requests
252
315
  */
@@ -308,5 +371,5 @@ function createAppManifest(appConfig) {
308
371
  };
309
372
  }
310
373
 
311
- export { Studio, StudioHeaders, createAppManifest, Studio as default };
374
+ export { Studio, StudioHeaders, types as StudioTypes, createAppManifest, Studio as default };
312
375
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/net/fetch.ts","../src/net/http.ts","../src/resources/actions.ts","../src/resources/lotItems.ts","../src/resources/lots.ts","../src/resources/markets.ts","../src/resources/sales.ts","../src/resources/webhooks.ts","../src/resources.ts","../src/studio.ts","../src/types.ts","../src/createApp.ts"],"sourcesContent":["export default function getFetch() {\n if (typeof fetch === \"undefined\") {\n throw new Error(\"fetch is not defined. Please use a polyfill.\");\n }\n return fetch;\n}\n","export default function SimpleHttpClient(\n baseUrl: string,\n apiKey: string,\n fetch: any,\n defaultTimeout: number,\n debug: boolean = false\n) {\n async function request<T>(method: string, path: string, body?: any) {\n let controller = new AbortController();\n\n let t = setTimeout(() => {\n controller.abort();\n\n if (debug) {\n console.log(`[SimpleHttpClient] ${method} ${path} timed out`);\n }\n }, defaultTimeout);\n\n let requestInit: any = {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n signal: controller.signal,\n };\n\n if (body) {\n requestInit.body = typeof body === \"string\" ? body : JSON.stringify(body);\n }\n\n if (debug) {\n let info: any = {};\n if (requestInit.headers) {\n info.headers = requestInit.headers;\n }\n if (requestInit.body) {\n info.body = requestInit.body;\n }\n\n console.log(`[SimpleHttpClient] ${method} ${baseUrl}${path}`, info);\n }\n\n let response = await fetch(`${baseUrl}${path}`, requestInit);\n clearTimeout(t);\n\n if (debug) {\n console.log(\n `[SimpleHttpClient] ${method} ${path} response: ${response.status}`\n );\n }\n\n if (response.ok) {\n return response.json() as T;\n }\n\n if (response.status === 404) {\n throw new Error(`${baseUrl}${path} not found`);\n }\n\n throw new Error(\n `Request failed with status ${response.status}: ${await response.text()}}`\n );\n }\n\n return {\n get: async <T>(path: string, queryParams?: any) => {\n let query = queryParams\n ? `?${new URLSearchParams(queryParams).toString()}`\n : \"\";\n return request<T>(\"GET\", `${path}${query}`);\n },\n post: async <T>(path: string, body: any) => {\n return request<T>(\"POST\", path, body);\n },\n delete: async <T>(path: string) => {\n return request<T>(\"DELETE\", path);\n },\n };\n}\n\nexport type HttpClient = ReturnType<typeof SimpleHttpClient>;\n","// Path: studiojs/src/resources/markets.ts\n\nimport { createHmac } from \"crypto\";\nimport { HttpClient } from \"../net/http\";\n\nexport default function create(_: HttpClient) {\n const actions = {\n /***\n * This is used to construct the action from the request body\n *\n * @param body the request body\n * @param signature the signature of the request taken from the header\n * @param endpointSecret the pre-shared secret\n * @returns the action\n */\n constructAction: async (\n bodyAsBuffer: Buffer,\n signature: string,\n endpointSecret: string\n ) => {\n let rawBody = bodyAsBuffer.toString();\n\n let expectedSignature = createHmac(\"sha256\", endpointSecret)\n .update(rawBody)\n .digest(\"hex\");\n\n if (signature !== expectedSignature) {\n console.error(\n `Unable to construct action. Signature mismatch.`,\n signature,\n \"!=\",\n expectedSignature\n );\n throw new Error(`Unable to construct action. Signature mismatch.`);\n }\n\n try {\n return JSON.parse(rawBody);\n } catch (e) {\n throw new Error(`Unable to construct action. ${e}`);\n }\n },\n };\n\n return actions;\n}\n\nexport type Webhooks = ReturnType<typeof create>;\n","import { HttpClient } from \"../net/http\";\nimport { LotItem } from \"../types\";\n\nexport default function create(httpClient: HttpClient) {\n return {\n create: async (\n marketId: string,\n saleId: string,\n lotId: string,\n data: {\n attributes?: Record<string, any>;\n notes?: Array<{\n text: string;\n }>;\n metadata?: Record<string, any>;\n }\n ) => {\n return httpClient.post<LotItem>(\n `/${marketId}/sales/${saleId}/lots/${lotId}/items`,\n data\n );\n },\n update: async (\n marketId: string,\n saleId: string,\n lotId: string,\n itemId: string,\n data: {\n attributes?: Record<string, any>;\n index?: number;\n metadata?: Record<string, any>;\n }\n ) => {\n return httpClient.post<LotItem>(\n `/${marketId}/sales/${saleId}/lots/${lotId}/items/${itemId}`,\n data\n );\n },\n delete: async (\n marketId: string,\n saleId: string,\n lotId: string,\n itemId: string\n ) => {\n return httpClient.delete(\n `/${marketId}/sales/${saleId}/lots/${lotId}/items/${itemId}`\n );\n },\n };\n}\n\nexport type LotItems = ReturnType<typeof create>;\n","import { HttpClient } from \"../net/http\";\nimport { Lot } from \"../types\";\n\nexport default function create(httpClient: HttpClient) {\n return {\n get: async (marketId: string, saleId: string, lotId: string) => {\n return httpClient.get<Lot>(`/${marketId}/sales/${saleId}/lots/${lotId}`);\n },\n list: async (marketId: string, saleId: string) => {\n return httpClient.get<Lot[]>(`/${marketId}/sales/${saleId}/lots`);\n },\n create: async (\n marketId: string,\n saleId: string,\n data: {\n index?: number;\n lotNumber?: string;\n group?: string;\n productCode?: string;\n sellerCustomerId?: string;\n attributes?: Record<string, any>;\n metadata?: Record<string, any>;\n buyerCustomerId?: string;\n unitPriceInCents?: number;\n startedAt?: string;\n endedAt?: string;\n previousLotNumber?: string;\n }\n ) => {\n return httpClient.post<Lot>(`/${marketId}/sales/${saleId}/lots`, data);\n },\n update: async (\n marketId: string,\n saleId: string,\n lotId: string,\n data: {\n productCode?: string;\n attributes?: Record<string, any>;\n sellerCasual?: string | null;\n sellerCustomerId?: string | null;\n lotNumber?: string | null;\n remarks?: string;\n notes?: string;\n unitOfSale?: \"Per KG\" | \"Per Item\" | \"Per Lot\" | \"Per 1000KG\";\n unitPriceInCents?: number;\n buyerCasual?: string | null;\n buyerCustomerId?: string | null;\n startedAt?: string | null;\n endedAt?: string | null;\n saleStatus?: \"Sold\" | \"Unsold\" | \"Rerun\" | \"Resold\" | null;\n metadata?: Record<string, any>;\n }\n ) => {\n return httpClient.post<Lot>(\n `/${marketId}/sales/${saleId}/lots/${lotId}`,\n data\n );\n },\n delete: async (marketId: string, saleId: string, lotId: string) => {\n return httpClient.delete(`/${marketId}/sales/${saleId}/lots/${lotId}`);\n },\n };\n}\n\nexport type Lots = ReturnType<typeof create>;\n","import { HttpClient } from \"../net/http\";\nimport { Market } from \"../types\";\n\nexport default function create(httpClient: HttpClient) {\n const markets = {\n get: async (marketId: string) => {\n return httpClient.get<Market>(`/${marketId}`);\n },\n // update: async (marketId: string, market: Partial<Market>) => {\n // // return httpClient.put<Market>(`/${marketId}`, market);\n // },\n // create: async (market: Market) => {\n // // return httpClient.post<Market>(\"/\", market);\n // },\n // //\n // watch: async (marketId: string, callback: (market: Market) => void) => {\n // // return httpClient.post<Market>(`/${marketId}/watch`);\n // },\n // hint: async (marketId: string, callback: () => void) => {\n // // return httpClient.post<Market>(`/${marketId}/hint`);\n // },\n };\n\n return markets;\n}\n\nexport type Markets = ReturnType<typeof create>;\n","import { HttpClient } from \"../net/http\";\nimport { Sale } from \"../types\";\n\ntype SalesListResponse = {\n start: string;\n end: string;\n sales: Sale[];\n};\n\nexport default function create(httpClient: HttpClient) {\n return {\n get: async (marketId: string, saleId: string) => {\n return httpClient.get<Sale>(`/${marketId}/sales/${saleId}`);\n },\n list: async (\n marketId: string,\n opts: {\n start?: string;\n end?: string;\n }\n ) => {\n return httpClient.get<SalesListResponse>(`/${marketId}/sales`, opts);\n },\n update: async (\n marketId: string,\n saleId: string,\n data: {\n name?: string;\n recurring?: \"Weekly\" | \"Bi-weekly\" | \"Monthly\" | null;\n defaultProductCode?: string;\n attributeDefaults?: Record<string, any>;\n martEyeId?: string | null;\n marteyeSettings?: {\n description?: string;\n image?: string;\n logo?: string;\n type: \"LIVE\" | \"TIMED\";\n location?: string | null;\n descriptionLines?: string[];\n descriptionLink?: string;\n deposit?: number;\n hidePrices?: boolean;\n hideReplay?: boolean;\n labels?: string[];\n tags?: string[];\n details?: Array<{\n markdownBase64: string;\n title: string;\n }>;\n cover?: string;\n primaryColour?: string;\n secondaryColour?: string;\n foregroundColour?: string;\n extensionTime?: number;\n incrementLadder?: Array<{\n max: number;\n increment: number;\n }>;\n hideNav?: boolean;\n signInOverrideLink?: string;\n published?: boolean;\n pin?: boolean;\n cascade?: boolean;\n reportEmail?: string;\n } | null;\n }\n ) => {\n return httpClient.post<Sale>(`/${marketId}/sales/${saleId}`, data);\n },\n };\n}\n\nexport type Sales = ReturnType<typeof create>;\n","// Path: studiojs/src/resources/markets.ts\n\nimport { createHmac } from \"crypto\";\nimport { HttpClient } from \"../net/http\";\n\nexport default function create(_: HttpClient) {\n const webhooks = {\n /***\n * This is used to construct the webhook event from the request body\n * @param body the request body\n * @param signature the signature of the request taken from the header\n * @param endpointSecret the pre-shared secret\n * @returns the webhook event\n */\n constructEvent: async (\n bodyAsBuffer: Buffer,\n signature: string,\n endpointSecret: string\n ) => {\n let rawBody = bodyAsBuffer.toString();\n\n let expectedSignature = createHmac(\"sha256\", endpointSecret)\n .update(rawBody)\n .digest(\"hex\");\n\n if (signature !== expectedSignature) {\n console.error(\n `Unable to construct event. Signature mismatch.`,\n signature,\n \"!=\",\n expectedSignature\n );\n throw new Error(`Unable to construct event. Signature mismatch.`);\n }\n\n try {\n return JSON.parse(rawBody);\n } catch (e) {\n throw new Error(`Unable to construct event. ${e}`);\n }\n },\n };\n\n return webhooks;\n}\n\nexport type Webhooks = ReturnType<typeof create>;\n","import { HttpClient } from \"./net/http\";\n\nimport actions from \"./resources/actions\";\nimport lotItems from \"./resources/lotItems\";\nimport lots from \"./resources/lots\";\nimport markets from \"./resources/markets\";\nimport sales from \"./resources/sales\";\nimport webhooks from \"./resources/webhooks\";\n\nexport default function resources(httpClient: HttpClient) {\n return {\n markets: markets(httpClient),\n sales: sales(httpClient),\n lots: lots(httpClient),\n lotitems: lotItems(httpClient),\n webhooks: webhooks(httpClient),\n actions: actions(httpClient),\n };\n}\n","import getFetch from \"./net/fetch\";\nimport HttpClient from \"./net/http\";\nimport Resources from \"./resources\";\n\nconst BaseUrl = \"https://www.marteyestudio.com/api\";\nconst DefaultTimeout = 10000;\n\nexport function Studio(\n apiKey: string,\n baseUrl: string = BaseUrl,\n defaultTimeout: number = DefaultTimeout,\n debug: boolean = false\n) {\n let httpClient = HttpClient(\n baseUrl,\n apiKey,\n getFetch(),\n defaultTimeout,\n debug\n );\n\n return {\n ...Resources(httpClient),\n isDebugMode: debug,\n };\n}\n","type Timestamp = string; // ISO 8601\r\n\r\n// dicates vat and commission applicatble to the line item\r\nexport type ClientType = \"Seller\" | \"Buyer\";\r\n\r\nexport type SuperType =\r\n | \"Sheep\"\r\n | \"Goats\"\r\n | \"Cattle\"\r\n | \"Pigs\"\r\n | \"Horses\"\r\n | \"Deer\"\r\n | \"Poultry\"\r\n | \"Machinery\"\r\n | \"Antiques\"\r\n | \"Other\";\r\n\r\nexport const SupportedSuperTypes: SuperType[] = [\r\n \"Sheep\",\r\n \"Goats\",\r\n \"Cattle\",\r\n \"Pigs\",\r\n \"Horses\",\r\n \"Deer\",\r\n \"Poultry\",\r\n \"Machinery\",\r\n \"Antiques\",\r\n \"Other\",\r\n];\r\nexport const LivestockSuperTypes: SuperType[] = [\r\n \"Sheep\",\r\n \"Goats\",\r\n \"Cattle\",\r\n \"Pigs\",\r\n \"Horses\",\r\n \"Deer\",\r\n \"Poultry\",\r\n];\r\n\r\nexport type Currency = \"GBP\" | \"EUR\" | \"USD\";\r\nexport const SupportedCurrencyCodes: Currency[] = [\"GBP\", \"EUR\", \"USD\"];\r\n// ISO 3166-2:GB\r\nexport type SupportedCountryCode =\r\n | \"GB-ENG\"\r\n | \"GB-SCT\"\r\n | \"GB-WLS\"\r\n | \"GB-NIR\"\r\n | \"IE\";\r\nexport type CurrenciesWithGuinea = Currency | \"GUINEA-GBP\";\r\n\r\nexport type UnitOfSale =\r\n | \"Per KG\"\r\n | \"Per Item\" /* aka 'per head'*/\r\n | \"Per Lot\"\r\n | \"Per 1000KG\";\r\nexport const SupportedUnitsOfSale: UnitOfSale[] = [\r\n \"Per KG\",\r\n \"Per Item\",\r\n \"Per Lot\",\r\n \"Per 1000KG\",\r\n];\r\nexport type PaymentMethod =\r\n | \"BACS\"\r\n | \"Cheque\"\r\n | \"BankTransfer\"\r\n | \"Cash\"\r\n | \"Card\"\r\n | \"Credit\"; // contra\r\n\r\nexport type PayoutMethod = \"BACS\" | \"Cheque\" | \"Cash\";\r\n\r\nexport const SupportedPaymentMethods: PaymentMethod[] = [\r\n \"BACS\",\r\n \"Cheque\",\r\n \"BankTransfer\",\r\n \"Cash\",\r\n \"Card\",\r\n \"Credit\",\r\n];\r\n\r\nexport interface Market {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n\r\n name: string;\r\n description: string;\r\n\r\n logo: string;\r\n primaryColour: string;\r\n secondaryColour: string;\r\n\r\n countryCode: SupportedCountryCode;\r\n\r\n address: Address;\r\n\r\n telephone?: string;\r\n vatNumber?: string;\r\n email?: string;\r\n\r\n movementLocationNumbers?: {\r\n number: string;\r\n type: \"CPH\" | \"Herd Number\" | \"Flock Number\" | \"Other\";\r\n // the issuing country that the holding number is valid for\r\n createdAt: Timestamp;\r\n }[];\r\n\r\n // Displayed on the invoice and other documents\r\n paymentInstructions?: string;\r\n\r\n // --/ settings\r\n}\r\n\r\nexport interface SettingsMarketDefaults {\r\n updatedAt: Timestamp;\r\n updatedBy: string | null;\r\n marketId: string;\r\n\r\n name: string;\r\n description: string;\r\n address: Address;\r\n defaultCurrency: Currency;\r\n defaultPayoutPreference: PayoutMethod;\r\n defaultUnitOfSale: UnitOfSale; // the fallback if the product code doesn't have one\r\n\r\n defaultSuperType?: SuperType | null;\r\n\r\n lotDescriptionTemplateMap?: {\r\n default: string | undefined;\r\n [supertype: string]: string | undefined;\r\n };\r\n\r\n rostrumAttributesMap?: {\r\n default: string[] | undefined;\r\n [supertype: string]: string[] | undefined;\r\n };\r\n\r\n // When printing all docs are not selected by default\r\n // You can override that here for whole classes of supertypes\r\n // Add the ID to deselect it when printing. This can be overridden product code\r\n // the most specific setting will be used\r\n selectDocumentIdsMap: {\r\n [supertype: string]: string[];\r\n };\r\n}\r\n\r\nexport interface SettingsProductCodes {\r\n [code: string]: ProductCodeConfiguration;\r\n}\r\n\r\nexport interface SettingsTaxRates {\r\n [id: string]: TaxRate;\r\n}\r\n\r\nexport interface SettingsAdjustmentsConfiguration {\r\n [id: string]: AdjustmentsConfiguration;\r\n}\r\n\r\nexport interface SettingsAccessories {\r\n [id: string]: Accessory;\r\n}\r\n\r\nexport interface SettingsPrinters {\r\n [id: string]: Printer;\r\n}\r\n\r\nexport type DeviceType = \"globeWeigh\" | \"allflexRaceReader\";\r\n\r\nexport interface Accessory {\r\n deviceId: string;\r\n deviceType: DeviceType;\r\n friendlyName: string;\r\n endOfMessagePattern: string;\r\n host: string;\r\n isEnabled: boolean;\r\n port: number;\r\n regex: string;\r\n saleProfileId: string;\r\n timeoutMs: number;\r\n updatedAt: Timestamp;\r\n createdAt: Timestamp;\r\n}\r\n\r\n/**\r\n * @description Configuration for the printer\r\n */\r\nexport interface Printer {\r\n id: string; // our unique id for the printer may include Tray at end if multiple trays\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n\r\n /**\r\n * @description The name of the printer. Its the same as the id\r\n */\r\n name: string; // name of the printer which is used by pdf-to-printer\r\n friendlyName: string; // friendly name e.g. Printer In Office\r\n chequePrinter?: boolean;\r\n /**\r\n * The next cheque number to use when printing a cheque\r\n */\r\n nextChequeNumber?: number;\r\n lastPrintedAt?: Timestamp;\r\n lastPrinterMessage?: string;\r\n}\r\n\r\n// in global studio settings\r\nexport interface SettingsGlobalAttributes {\r\n [id: string]: AttributeDefinition;\r\n}\r\n\r\nexport type AttributeValueType = string | number | boolean | Timestamp | Media;\r\n\r\n/****\r\n * Used to grant a user access to a market.\r\n * Each member of staff should have their own.\r\n */\r\nexport interface MemberSharingConfiguration {\r\n uid: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n\r\n displayName?: string;\r\n photoURL?: string;\r\n\r\n marketId: string;\r\n // only one owner per market.\r\n role: \"Owner\" | \"Admin\" | \"Editor\";\r\n}\r\n\r\nexport interface Sale {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n startsAt: Timestamp;\r\n\r\n closedAt?: Timestamp | null;\r\n\r\n // The owner of the sale\r\n marketId: string;\r\n\r\n // \"Weekly Dairy Sale\" / \"Fat Lambs, Hoggets & Fat Ewes\" etc\r\n name: string;\r\n\r\n recurring?: null | \"Weekly\" | \"Bi-weekly\" | \"Monthly\";\r\n\r\n defaultProductCode: string;\r\n\r\n /**\r\n * Default attributes values for any new lot item\r\n */\r\n attributeDefaults?: {\r\n [attributekey: string]: AttributeValueType;\r\n };\r\n\r\n /**\r\n * the codes that are allowed for the sale\r\n */\r\n availableProductCodes: string[];\r\n\r\n /**\r\n * the supertypes from the product codes. e..g Cattle, Sheep, Pigs etc\r\n */\r\n superTypes: SuperType[];\r\n\r\n // Either the string ID for a known item attibute (begins with an @) or a custom attribute\r\n attributeSet: AttributeDefinition[];\r\n\r\n // Not all attributes are valid for all products\r\n attributeSetByProductCode: {\r\n [code: string]: string[];\r\n };\r\n\r\n // The ID of the group of lots that are currently being sold (for a live sale)\r\n currentLotGroup?: string | null;\r\n // The ID of the group the clerk has queued up next\r\n nextLotGroup?: string | null;\r\n\r\n /**\r\n * Auto queue the next lot when the current lot is sold in rostrum\r\n */\r\n autoQueue?: boolean;\r\n\r\n /**\r\n * The sale profile ID to use for this sale. Which is used to find settings specific devices and printers etc.\r\n */\r\n saleProfileId?: string | null;\r\n\r\n /**\r\n * Show the display board\r\n */\r\n displayBoard?: boolean;\r\n /// folllow on sale ? TBD\r\n\r\n // MartEye Live details\r\n martEyeId?: string | null; // null === not on MartEye\r\n marteyeSettings?: MartEyeTimedSaleSettings | MartEyeLiveSaleSettings | null;\r\n}\r\n\r\nexport interface MartEyeLiveSaleSettings {\r\n description?: string;\r\n image?: string;\r\n logo?: string;\r\n type: \"LIVE\";\r\n\r\n // If you want to oveeride the marts name as the location\r\n location?: string | null;\r\n\r\n // Optional free text used in the info tab on the catalogue page\r\n descriptionLines?: string[];\r\n // optional link to an external catalogue\r\n descriptionLink?: string;\r\n\r\n deposit?: number;\r\n\r\n // true if prices should be hidden after the sale\r\n hidePrices?: boolean;\r\n\r\n // true if we dont want to show replay videos\r\n hideReplay?: boolean;\r\n\r\n labels?: string[];\r\n tags?: string[];\r\n}\r\n\r\nexport interface MartEyeTimedSaleSettings {\r\n description?: string;\r\n // URL of the image to display on the tile\r\n image?: string;\r\n // An override for the logo on the tile\r\n logo?: string;\r\n type: \"TIMED\";\r\n\r\n /**\r\n * The location of the sale. This could be a physical location Ring 1 / Ring 2 / Farm Address etc\r\n */\r\n location?: string | null;\r\n\r\n // The details to go on the front page\r\n details?: { markdownBase64: string; title: string }[];\r\n\r\n // the url for the cover image\r\n cover?: string;\r\n\r\n // dominant colour used for things like the nav bar\r\n primaryColour?: string;\r\n // used for things like the tab bar\r\n secondaryColour?: string;\r\n // the colour used for text or tabbar indicator\r\n foregroundColour?: string;\r\n\r\n // The number of seconds to extend a lot by when there's a last min bid\r\n extensionTime: number;\r\n\r\n // the increments and break points to go up in\r\n incrementLadder: IncrementLadder;\r\n\r\n // if true remove the nav bar on desktop\r\n hideNav?: boolean;\r\n\r\n // a link to send people to when they click the sign in button\r\n signInOverrideLink?: string;\r\n\r\n // should show on main page\r\n published?: boolean;\r\n\r\n // true if should pin to the top of the list\r\n pin?: boolean;\r\n\r\n // labels to show on the tile. Different to tags\r\n labels?: string[];\r\n\r\n // if provided will request that the user submits a deposit\r\n deposit?: number;\r\n\r\n // If true each lot will only being ending once the one before it has closed\r\n cascade?: boolean;\r\n\r\n // comma seperated people to send the report to\r\n reportEmail?: string;\r\n}\r\n\r\nexport type IncrementLadder = IncrementLadderItem[];\r\n\r\nexport interface IncrementLadderItem {\r\n max: number;\r\n increment: number;\r\n}\r\n\r\nexport interface SaleFromSearch\r\n extends Omit<Omit<Omit<Sale, \"createdAt\">, \"updatedAt\">, \"startsAt\"> {\r\n createdAt: number;\r\n updatedAt: number;\r\n startsAt: number;\r\n}\r\n\r\nexport type LotSaleStatus = \"Sold\" | \"Unsold\" | \"Rerun\" | \"Resold\" | null;\r\n\r\nexport interface Lot {\r\n id: string; // unique for the sale? Could be saleId + lotNumber\r\n saleId: string;\r\n marketId: string;\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n // the item code of the lot. This is used to determine the commission rate and the display board\r\n // a lot can only contain items with the same product code (you can think of it as a product type)\r\n productCode: string;\r\n // / Set by a cloud function\r\n superType?: SuperType;\r\n // subtype?: ProductSubtype;\r\n isLivestock?: boolean;\r\n // \\ Set by a cloud function\r\n\r\n attributes: {\r\n [key: string]: AttributeValueType;\r\n };\r\n\r\n // if present here than the attribute is loading in\r\n // remove to signify it has loaded\r\n loadingAttributes?: {\r\n [attributePath: string]: {\r\n id: string;\r\n // time loading began\r\n startAt: Timestamp;\r\n // the path to the attribute (may be on an item)\r\n path: string;\r\n };\r\n };\r\n\r\n itemMap: {\r\n [itemId: string]: LotItem;\r\n };\r\n\r\n sellerCasual?: string | null;\r\n sellerCustomerId: string | null;\r\n seller?: ShortCustomerDetails;\r\n\r\n lotNumber?: string | null;\r\n // The sort order of the lot within the sale\r\n index: number;\r\n // More than one lot can be sold in the ring at once. This groups the lots. Convention to use the earliest lot number in the group as the group ID\r\n group?: string;\r\n\r\n // Free text description of the lot. Intended to be customer facing.\r\n remarks?: string;\r\n\r\n // free text notes, not customer facing possible not needed.\r\n notes?: string;\r\n\r\n // Sale config\r\n currency: CurrenciesWithGuinea;\r\n\r\n unitOfSale: UnitOfSale;\r\n\r\n // --- Sale record\r\n\r\n unitPriceInCents?: number;\r\n\r\n // This could be any free text that the clerk input on the rostrum. It can be thought of as a note for someone to look up the actual buyer later\r\n buyerCasual?: string | null;\r\n buyerCustomerId: string | null;\r\n buyer?: ShortCustomerDetails | null;\r\n\r\n // The time the lot entered and left the ring\r\n startedAt?: Timestamp;\r\n endedAt?: Timestamp;\r\n\r\n // must be set, the null used to find records that have not been invoiced\r\n sellerInvoiceId: string | null;\r\n sellerInvoiceNumber?: number | undefined | null;\r\n // must be set, used to find records that have not been invoiced\r\n buyerInvoiceId: string | null;\r\n buyerInvoiceNumber?: number | undefined | null;\r\n\r\n // If an invoice is voided, we keep a record of the ID here\r\n voidedSellerInvoiceIds?: string[];\r\n voidedBuyerInvoiceIds?: string[];\r\n\r\n // in the case when a lot is unsold.\r\n // The seller gets and invoice but the buyer does not.\r\n saleStatus?: LotSaleStatus;\r\n // ignore the result of this lot. Likely because rerun or resold\r\n void?: boolean;\r\n // if this lot was created from a rerun or resell, this is the ID of the original lot\r\n originalLot?: string;\r\n\r\n // -- /Sale record\r\n\r\n metadata: {\r\n [key: string]: any;\r\n };\r\n\r\n // These are controlled by a cloud function\r\n generated?: LotGeneratedValues;\r\n\r\n // Issues with a lot can be raised asyncronously and resolved later.\r\n issues?: {\r\n [issueId: string]: LotIssue;\r\n };\r\n\r\n resolvedIssues?: {\r\n [issueId: string]: LotIssue;\r\n };\r\n\r\n /***\r\n * Default values for any new lot item\r\n */\r\n itemAttributeDefaults?: {\r\n [attributekey: string]: AttributeValueType;\r\n };\r\n}\r\n\r\ntype LotIssueCode =\r\n | \"unknown-attribute\" // attribute ID is invalid or not setup for this sale\r\n | \"validation-error\" // serverside validation error\r\n | \"staff-flagged\"; // a staff member has raised an issue with the lot that needs to be resovled\r\n\r\nexport interface LotIssue {\r\n id: string;\r\n // optional. If the issue is specific to an item then this is the ID of the item\r\n itemId?: string | null;\r\n // optional. The path to the parameter that caused the issue\r\n path?: string | null;\r\n code: LotIssueCode;\r\n // The issue description\r\n description: string;\r\n // The issue severity\r\n severity: \"error\" | \"warning\" | \"info\";\r\n createdAt: Timestamp;\r\n // Who created the issue\r\n createdBy: string;\r\n // If there is an approval required for this lo\r\n blockCheckout: boolean;\r\n}\r\n\r\nexport interface LotWithItemsAsArray extends Omit<Lot, \"itemMap\"> {\r\n items: LotItem[];\r\n}\r\n\r\nexport interface LotGeneratedValues {\r\n // The total value of the lot in cents\r\n totalValueInCents?: number | null;\r\n\r\n // a description we can use in the cart and on the invoice\r\n description?: string | null;\r\n\r\n // We carry these through to the invoice as averages\r\n pricePerKiloInCents?: number | null;\r\n averageWeightKg?: number | null;\r\n pricePerItemInCents?: number | null;\r\n\r\n countOfItems?: number | null;\r\n}\r\n\r\n// To save a lookup to the customer document we store a copy of the customer details in the lot taken at the time it was added\r\n// Whilst the customer may change their details later it's actually a useful feature not to go back and update the lot with the change\r\nexport interface ShortCustomerDetails {\r\n // true if the customer record has been found and copied in\r\n // false if the customer could not be found\r\n isSet: boolean;\r\n\r\n id?: string;\r\n copiedInAt?: Timestamp;\r\n accountNumber?: string;\r\n bidderNumber?: number | null;\r\n displayName?: string;\r\n\r\n // unsued on everything but the market\r\n avatar?: string | null;\r\n}\r\n\r\n// note the item does not have it's own document in firestore. It exists inside the Lot\r\nexport interface LotItem {\r\n id: string; // unique ID but it wont be created by firestore\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n index: number;\r\n\r\n attributes: {\r\n [key: string]: AttributeValueType;\r\n };\r\n\r\n notes: {\r\n id: string;\r\n text: string;\r\n createdAt: Timestamp;\r\n }[];\r\n\r\n metadata: {\r\n // Interesting things to add here could be:\r\n // - time the item was scanned in\r\n // - photos of the entry forms\r\n // - links to clips generated\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n}\r\n\r\n/***\r\n * A market may offer other products and services. This is a way to track those.\r\n * They simply create a line item on the invoice\r\n *\r\n * /settings/products\r\n */\r\nexport interface Product {\r\n id: string;\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n marketId: string;\r\n\r\n name: string;\r\n taxRateId: string;\r\n defaultUnitPriceInCents: number;\r\n\r\n unitPriceIncludesVat?: boolean;\r\n\r\n // The type of client this config applies too. If empty applies to all client types\r\n applyToClients: ClientType[];\r\n\r\n // line items with the same code are given a subtotal for the group on the invoice\r\n subtotalGroup?: SubtotalGroups | null | undefined;\r\n\r\n // true if this product supports routing this money to another customer (say a dealer or haulier)\r\n passThroughFundsToAnotherCustomer?: boolean;\r\n\r\n // Is the product enabled\r\n isEnabled?: boolean;\r\n\r\n metadata: {\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n}\r\n\r\n/***\r\n * When a product is added to a cart it becomes a CartProductItem\r\n *\r\n *\r\n * markets/ballymena/carts/{userId}\r\n *\r\n * {id: CartItem}\r\n */\r\nexport interface CartItem {\r\n id: string; // unique ID but it wont be created by firestore\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n marketId: string;\r\n customerId: string;\r\n\r\n // The ID of the product\r\n productId: string;\r\n\r\n clientType: ClientType;\r\n // The quantity of the product\r\n quantity: number;\r\n\r\n // The total price of the product\r\n unitPriceInCents: number;\r\n\r\n // If the product supports routing this money to another customer (say a dealer or haulier)\r\n // then this is the ID of the customer to send the funds to\r\n passthroughFundsToCustomerId?: string | null;\r\n\r\n generated?: {\r\n totalInCents: number;\r\n };\r\n}\r\n\r\n/***\r\n * Items have codes. And those codes are used to apply the correct commission rates, report movements etc.\r\n */\r\nexport interface ProductCodeConfiguration {\r\n // Unique for the market, is the ID for the document\r\n code: string;\r\n\r\n createdAt?: Timestamp;\r\n updatedAt?: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n // Integrations will use this for determining if this item needs to have movements reported etc\r\n superType: SuperType;\r\n\r\n // subtype?: ProductSubtype;\r\n\r\n description: string;\r\n\r\n // Name for the icon to use in the UI\r\n icon?: string;\r\n\r\n // A set of expected attributes needed for the catalogue\r\n // attributes?: string[];\r\n\r\n metadata: {\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n\r\n // -- invoices\r\n // - the following generate line items for the invoice.\r\n // - They can be removed or changed manually by the user\r\n\r\n // id for a TaxRate record\r\n // Users shoudl be able to override this on the invoice later\r\n // e.g. people may have different tax rates if they live in another country\r\n taxRateId: string;\r\n\r\n // groups up on the subtotal lines on the invoice\r\n // leave null if grouping isn't needed\r\n subtotalGroup?: SubtotalGroups | null;\r\n\r\n // extra charges to apply on the invoice (e.g. commission, levies etc)\r\n // IDs for AdjustmentsConfiguration records\r\n adjustmentIds: string[];\r\n\r\n // If the price is inclusive of VAT\r\n // We need to for IE as it is assumed the hammer price includes VAT\r\n // default false\r\n unitPriceIncludesVat?: boolean;\r\n\r\n totalExVatRebatePecentage?: number;\r\n\r\n // These carry over to the lots\r\n defaultCurrency?: CurrenciesWithGuinea; // if empty, defaults to market currency\r\n defaultUnitOfSale: UnitOfSale;\r\n\r\n // if provided, the lot will default to this product code when created\r\n // if the number is within this range\r\n defaultLotRange?: {\r\n min: number;\r\n max: number;\r\n };\r\n\r\n // These are copied over to new lots and lot items when created\r\n // item level attributes are prefixed \"@\"\r\n attributeDefaults?: {\r\n [attributekey: string]: AttributeValueType;\r\n };\r\n\r\n // A handlebars template to use for the description on the invoice\r\n lotDescriptionTemplate?: string;\r\n\r\n // The attributes we want editable on the rostrum active page\r\n rostrumAttributes?: string[];\r\n\r\n // When printing all docs are not selected by default\r\n // You can override that here for lots of this product code\r\n selectDocumentIds?: string[] | null;\r\n}\r\n\r\n/***\r\n * How the products are stored in settings\r\n */\r\nexport interface ProductConfiguration {\r\n [id: string]: Product;\r\n}\r\n\r\n/***\r\n * A market may offer other products and services. This is a way to track those.\r\n * They simply create a line item on the invoice\r\n */\r\nexport interface Product {\r\n id: string;\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n marketId: string;\r\n\r\n name: string;\r\n taxRateId: string;\r\n defaultUnitPriceInCents: number;\r\n\r\n unitPriceIncludesVat?: boolean;\r\n\r\n // The type of client this config applies too. If empty applies to all client types\r\n applyToClients: ClientType[];\r\n\r\n // line items with the same code are given a subtotal for the group on the invoice\r\n subtotalGroup?: SubtotalGroups | null | undefined;\r\n\r\n // true if this product supports routing this money to another customer (say a dealer or haulier)\r\n passThroughFundsToAnotherCustomer?: boolean;\r\n\r\n // if this product relates to a lot then this is the lot ID\r\n // e.g. dealer charge for a lot\r\n relatedTo?: { lotId: string; saleId: string } | null;\r\n\r\n // if true, and a relatedTo is set, then the funds will be added to the lot total on the invoice\r\n obfusicate?: boolean;\r\n\r\n metadata: {\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n}\r\n\r\nexport interface Cart {\r\n updatedAt: Timestamp;\r\n itemsById: {\r\n [itemId: string]: CartItem;\r\n };\r\n}\r\n\r\nexport interface EmailWrapper {\r\n email: string;\r\n isVerified: boolean;\r\n createdAt: Timestamp;\r\n}\r\n\r\nexport interface PhoneNumberWrapper {\r\n phoneNumber: string;\r\n isVerified: boolean;\r\n createdAt: Timestamp;\r\n}\r\n\r\nexport interface AddressWrapper {\r\n address: Address;\r\n createdAt: Timestamp;\r\n updatedAt?: Timestamp;\r\n updatedBy?: string | null;\r\n}\r\n\r\nexport interface FarmAssurances {\r\n createdAt: Timestamp;\r\n updatedAt?: Timestamp;\r\n updatedBy?: string | null;\r\n memberReference: string;\r\n expiryDate: Timestamp;\r\n\r\n // TODO need the full list of scopes that Red Tractor use\r\n scope?: \"Beef\" | \"Dairy\" | \"Pork\" | \"Sheep\" | \"Other\";\r\n}\r\n\r\nexport type BankDetails = {\r\n accountName?: string; // Optional used to over ride the name of the account holder\r\n} & (\r\n | { accountNumber: string; sortCode: string; IBAN?: never } // Either accountNumber and sortCode without IBAN\r\n | { IBAN: string; accountNumber?: never; sortCode?: never }\r\n); // Or just IBAN without accountNumber and sortCode\r\n\r\n/**\r\n * Used to store the bank details for a market\r\n */\r\nexport type MarketBankDetails = {\r\n name: string; // The bank account owner\r\n bankId: string; // virgin/hsbc etc\r\n address: Address;\r\n} & (\r\n | { accountNumber: string; sortCode: string; IBAN?: never } // Either accountNumber and sortCode without IBAN\r\n | { IBAN: string; accountNumber?: never; sortCode?: never }\r\n); // Or just IBAN without accountNumber and sortCode\r\n\r\nexport interface Customer {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n\r\n updatedBy?: string | null;\r\n\r\n // The market this customer belongs to\r\n marketId: string;\r\n\r\n // Every market has one customer to represent themselves. If this it true this record is that account.\r\n // Another way to tell is that the ID for this document will be identical to the market ID\r\n isMarketAccount?: boolean;\r\n\r\n // The user's \"account\" with the market. Useful for quick look up + showing on invoices\r\n accountNumber?: string;\r\n // A unique number that can be used to identify the customer.\r\n // Possible that it's reset as soon as after each sale\r\n bidderNumber?: number | null;\r\n\r\n firstName?: string | null;\r\n lastName?: string | null;\r\n\r\n tradingName?: string | null;\r\n\r\n email?: EmailWrapper;\r\n phoneNumber?: PhoneNumberWrapper;\r\n otherPhoneNumbers?: PhoneNumberWrapper[];\r\n\r\n address: AddressWrapper;\r\n otherAddresses: {\r\n [addressId: string]: AddressWrapper;\r\n };\r\n\r\n photoURL?: string | null;\r\n\r\n payoutPreference?: PayoutMethod;\r\n bankDetails?: BankDetails;\r\n\r\n // Attributes to add to the lot when the customer is the seller/buyer\r\n // Here we have an array of attribute values. The most latest used is added to the\r\n // 0 position in the array. The other values could be shown in a dropdown for the user to select\r\n attributeDefaultsBuyer?: {\r\n [attributekey: string]: AttributeValueType[];\r\n };\r\n attributeDefaultsSeller?: {\r\n [attributekey: string]: AttributeValueType[];\r\n };\r\n\r\n // If true any debt on the account will be paid down first before paying out out a credit balance (cheque/BACS etc)\r\n // defaults to true. Some markets call this \"contra\"\r\n preferSettleDebtsFirst?: boolean;\r\n\r\n // People may or may not have VAT numbers. This will affect the tax calculation on their bill.\r\n // the VAT number is used to determine the country and has prefix GB, IE, DE etc. for specific countries\r\n vatNumber?: string;\r\n\r\n metadata: {\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n\r\n // If at any point this customer has bought or sold items in the market\r\n lastItemPurchaseDate?: Timestamp;\r\n lastItemSaleDate?: Timestamp;\r\n hasPurchasedItems?: boolean;\r\n hasSoldItems?: boolean;\r\n\r\n // Notes\r\n notes?: string;\r\n}\r\n\r\n// All Timestamps are replaced with a number\r\nexport interface CustomerFromSearch\r\n extends Omit<\r\n Customer,\r\n \"createdAt\" | \"updatedAt\" | \"lastItemPurchaseDate\" | \"lastItemSaleDate\"\r\n > {\r\n createdAt: number;\r\n updatedAt: number;\r\n\r\n // If at any point this customer has bought or sold items in the market\r\n lastItemPurchaseDate?: number;\r\n lastItemSaleDate?: number;\r\n}\r\n\r\nexport interface Address {\r\n id: string;\r\n nickname?: string;\r\n company?: string;\r\n firstName?: string;\r\n lastName?: string;\r\n address1: string;\r\n address2?: string;\r\n city: string;\r\n province?: string;\r\n zip: string;\r\n // ISO Country Code. Must include the sub-region if applicable (e.g. GB-ENG, GB-WLS, GB-NIR, GB-SCT)\r\n // this is the part that is needed for calculating tax on the invoice\r\n country: string;\r\n}\r\n\r\ninterface ImageThumbnail {\r\n url: string;\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface Media {\r\n id: string;\r\n\r\n url: string;\r\n type: \"image/jpeg\" | \"image/png\" | \"video/mp4\" | \"application/pdf\";\r\n filename: string;\r\n thumbnails?: {\r\n small?: ImageThumbnail;\r\n medium?: ImageThumbnail;\r\n large?: ImageThumbnail;\r\n };\r\n}\r\n\r\n//// --- Report Headers --- ////\r\n\r\nexport type MarketReportHeaders =\r\n | \"grossServices\"\r\n | \"vatOnServices\"\r\n | \"grossGoods\"\r\n | \"vatOnGoods\"\r\n | \"netTotal\"\r\n | \"contra\";\r\n\r\n// --- Invoices ---\r\n/**\r\n * Content types which will denote the position of the data on the invoice wihth out with a cheque\r\n */\r\n\r\n// a type used to define the position of the fields on the cheque\r\nexport type FieldPositions = {\r\n id: ChequeField | InvoiceField;\r\n x: number;\r\n y: number;\r\n};\r\n\r\nexport type InvoiceField =\r\n | \"invoiceNumber\"\r\n | \"invoiceDate\"\r\n | \"description\"\r\n | \"lotNumber\"\r\n | \"quantity\"\r\n | \"weight\"\r\n | \"unitPrice\"\r\n | \"grossLineTotal\"\r\n | \"accountRef\"\r\n | \"accountName\"\r\n | \"businessAddress\"\r\n | \"customerAddress\"\r\n | \"lineItemsStartLine\" // the line that table items start at\r\n | \"footerBoundaryLine\" // this marks the line of the cheque break if used\r\n | \"vatNumber\"\r\n | \"saleName\"\r\n | \"subTotal\" // the column of subtotals e.g. vat, livestock etc\r\n | \"subTotalTable\" // the table of subtotals e.g. vat, livestock etc\";\r\n | \"tagList\"\r\n | \"tagNumber\";\r\n\r\n// a list of fields that can be used to generate a cheque\r\nexport type ChequeField =\r\n | \"chequeDate\"\r\n | \"chequeNumber\"\r\n | \"payee\"\r\n | \"amount\"\r\n | \"amountInWords\"\r\n | \"hunderdsOfThousands\"\r\n | \"tensOfThousands\"\r\n | \"thousands\"\r\n | \"hundreds\"\r\n | \"tens\"\r\n | \"units\";\r\n\r\nexport type SubtotalGroups = \"Commission\" | string;\r\n\r\nexport type AdjustmentTotalTarget =\r\n | \"Per Invoice\"\r\n | \"Total - finalTotalInCents\"\r\n | \"Total - lotTotalLessCommissionInCentsExVat\";\r\n\r\nexport type AdjustmentTarget =\r\n | UnitOfSale\r\n // Apply after the totals have been calculated but before any other total adjustments\r\n | AdjustmentTotalTarget;\r\n\r\n/***\r\n * Commission is added as a line item. Can also be used for levies etc\r\n */\r\nexport interface AdjustmentsConfiguration {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n // a friendly name for the adjustment to be used in the UI\r\n name?: string | null;\r\n\r\n // // How the item appears on the invoice\r\n description?: string | null;\r\n\r\n // The type of client this config applies too. If empty applies to all client types\r\n applyToClients: ClientType[];\r\n\r\n // line items with the same code are given a subtotal for the group on the invoice\r\n subtotalGroup?: SubtotalGroups | null | undefined;\r\n\r\n // this dictates how the money is moved through the ledger\r\n // commission is an income for the market\r\n // a levy would be a \"liability\" as becomes a liability to be paid off later as an expense\r\n // \"vat-rebate\" will (eventually) move the money back into the VAT account\r\n type: \"commission\" | \"levy\" | \"vat-rebate\";\r\n\r\n // Selects where this commission config applies\r\n filter?: {\r\n // apply only to item with this currency\r\n currency?: CurrenciesWithGuinea | null;\r\n\r\n // Apply only between the min and max quantity range (inclusive).\r\n quantity?: {\r\n // default zero\r\n min?: number;\r\n // default Infinity\r\n max?: number;\r\n } | null;\r\n\r\n // Apply only between a min and max per item price\r\n unitPrice?: {\r\n // default zero\r\n minInCents?: number;\r\n // default Infinity\r\n maxInCents?: number;\r\n } | null;\r\n\r\n totalPrice?: {\r\n // default zero\r\n minInCents?: number;\r\n // default Infinity\r\n maxInCents?: number;\r\n } | null;\r\n\r\n // set true to apply this adjustment if a customer is vat registered in any tax region\r\n // false to apply if they are not vat registered\r\n // leave undefined or null to apply to all customers\r\n customerIsVATRegistered?: boolean | null;\r\n // set true to apply this adjustment if the customer is in the same tax region as the market\r\n // false to apply if they are not in the same tax region\r\n // leave undefined or null to apply to all customers\r\n customerWithinTaxRegion?: boolean | null;\r\n\r\n // Will apply if a lot or any items has the attribute key / value pair\r\n // e.g. \"onlineBuyer\" : true\r\n // note we only allow the simple attribute values\r\n attribute?: {\r\n key: string;\r\n // use null to filter for null or undefined values\r\n value: string | number | boolean | null;\r\n } | null;\r\n };\r\n\r\n // The ID of the tax rate that is applied to this adjustment\r\n taxRateId: string;\r\n\r\n adjustment: Adjustment & { target: AdjustmentTarget };\r\n}\r\n\r\ninterface Adjustment {\r\n percentage?: {\r\n // A value between 0-1.\r\n value?: number;\r\n // A minimum value the commision can be\r\n floorInCents?: number;\r\n // A cap for the heighest value a commision can be\r\n ceilingInCents?: number;\r\n } | null;\r\n\r\n // A single amount that is added if the filter applies.\r\n // Could be used for entry fees but likely need to seperate out the entry fee from the commission\r\n fixedAmountInCents?: number | null;\r\n}\r\n\r\nexport interface LineItemAdjustmentConfiguration\r\n extends AdjustmentsConfiguration {\r\n adjustment: Adjustment & { target: UnitOfSale };\r\n}\r\n\r\n// specifically for targeting invoice totals\r\nexport interface InvoiceTotalAdjustmentConfiguration\r\n extends AdjustmentsConfiguration {\r\n adjustment: Adjustment & { target: AdjustmentTotalTarget };\r\n}\r\n\r\n/***\r\n * Tax config is used to generate the invoice but the user can still edit the invoice, overriding the final values.\r\n */\r\nexport interface TaxRate {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n marketId: string;\r\n\r\n // description of the tax shown on the invoice\r\n description: string;\r\n\r\n // line items with the same code are given a subtotal for the group on the invoice\r\n // e.g. \"Tax on Services\" or \"VAT\"\r\n taxSubtotalGroup?: string | null;\r\n\r\n // A value between 0-1. This is the tax rate that will be applied\r\n percentage: number;\r\n\r\n // If true then this tax rate will override others if\r\n // customerIsVATRegistered === true\r\n // customerWithinTaxRegion === false\r\n //\r\n // (see the createDraftInvoice function)\r\n // There can be only one export tax rate. Validate in the UI.\r\n isExportTaxRate?: boolean;\r\n}\r\n\r\n// A payment into the market\r\nexport interface Payment {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string;\r\n\r\n transactionDate: Timestamp;\r\n\r\n marketId: string;\r\n // the customer who made the payment\r\n customerId: string;\r\n method: PaymentMethod;\r\n\r\n // note currency is always assumed to be the market currency\r\n amountInCents: number;\r\n // Should be what will appear on the mart's bank statement\r\n // for a cheque this is the cheque number\r\n // for bacs this is the reference number\r\n // for card this is the transaction reference\r\n // not always present (e.g. cash)\r\n reference: string | null;\r\n\r\n status: \"complete\" | \"void\";\r\n\r\n voidedAt?: Timestamp | null;\r\n voidedBy?: string | null;\r\n voidReason?: string | null;\r\n\r\n // Invoices that this payment went toward\r\n invoiceIds: string[];\r\n\r\n // The transactions that were created on the ledger for this\r\n transactionIds: string[];\r\n}\r\n\r\nexport interface Payout {\r\n id: string;\r\n marketId: string;\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy: string | null;\r\n customerId: string;\r\n // Credit only allowed for payouts created by the system\r\n method: PayoutMethod | \"Credit\";\r\n amountInCents: number;\r\n\r\n // for BACS these are present\r\n accountName?: string; // usually the customer's name\r\n accountNumber?: string;\r\n sortCode?: string;\r\n\r\n // for cheque these are present\r\n chequeMadePayableTo?: string;\r\n\r\n transactionDate: Timestamp;\r\n reference: string | null;\r\n status: \"pending\" | \"complete\" | \"void\";\r\n notes: string | null;\r\n\r\n completedAt?: Timestamp | null;\r\n completedBy?: string | null;\r\n\r\n voidedAt?: Timestamp | null;\r\n voidedBy?: string | null;\r\n voidReason?: string | null;\r\n\r\n // The transactions that were created on the ledger for this\r\n transactionIds: string[];\r\n\r\n // The invoices paid by this payout\r\n invoiceIds: string[];\r\n}\r\n\r\nexport interface DraftInvoice extends InvoiceTotals {\r\n // the ID is deterministic so saving can be made idempotent\r\n id: string;\r\n\r\n currency: Currency;\r\n\r\n status: \"draft\";\r\n\r\n // the time the invoice was sent\r\n issuedAt?: Timestamp;\r\n\r\n // the identifiers for the lots the invoice is for\r\n lotIdents: { lotId: string; saleId: string }[];\r\n // buyer or seller\r\n clientType: ClientType;\r\n\r\n customerId: string;\r\n customerAccountNumber: string;\r\n\r\n // The name of the customer or trading name to go on the invoice\r\n name: string;\r\n // The customer's address that was used for this invoice.\r\n // The address influences how tax is calculated\r\n address: Address;\r\n email: string | null;\r\n\r\n // the super type of the invoice sheep or cattle etc\r\n superTypes?: SuperType[];\r\n\r\n // The settings around tax used to generate the invoice\r\n customerIsVATRegistered: boolean;\r\n customerWithinTaxRegion: boolean;\r\n\r\n // the line items that make up the invoice\r\n lineItems: InvoiceLineItem[];\r\n // adjustments are added as line items. Can also be used for levies etc\r\n adjustmentLineItems: InvoiceLineItem[];\r\n\r\n // the vat number of the client is required for the invoice if its going for export\r\n vatNumber?: string;\r\n\r\n // the IDs for any extra products that were added onto this invoice\r\n extraProductIds: string[];\r\n\r\n // if a seller, the preferred payout method for this invoice\r\n payoutMethod?: PayoutMethod | null;\r\n payoutParams?: {\r\n // default true, if any debts should be tackled first\r\n settleDebtsFirst: boolean;\r\n\r\n // For BACS\r\n accountName?: string;\r\n accountNumber?: string;\r\n sortCode?: string;\r\n\r\n // For cheque\r\n chequeMadePayableTo?: string;\r\n };\r\n\r\n // The exact payouts wont be accurate until the invoice is finalised\r\n potentialPayoutsById?: {\r\n [payoutId: string]: {\r\n id: string;\r\n amountInCents: number;\r\n paymentMethod: PaymentMethod;\r\n invoice?: {\r\n // included if this payout will pay off an invoice\r\n id: string;\r\n invoiceNumber: number;\r\n fullyPaid: boolean;\r\n };\r\n };\r\n };\r\n\r\n // We may need to collect some info for the lots at checkout (e.g. destination address)\r\n // atrributes here will get set onto the relevant lots once the invoice is created\r\n attributeValues?: {\r\n [attributekey: string]: AttributeValueType;\r\n };\r\n\r\n // The attributes to collect\r\n attributes: AttributeDefinition[];\r\n\r\n // customisable, shown on the invoice\r\n averages?: { label: string; value: number; formattedValue: string }[];\r\n\r\n paymentInstructions?: string | null;\r\n}\r\n\r\nexport interface InvoiceTotals {\r\n //the lot total in cents\r\n lotTotalInCentsExVat: number;\r\n\r\n // the vat on the lot total in cents\r\n vatOnLotTotalInCents: number;\r\n\r\n // this calcluates the total commission from commissionLineItems exlusive of vat\r\n commissionTotalInCents?: number;\r\n // VAT on commission in cents. Needs to be seperate to allow for vat margin scheme\r\n vatOnCommissionInCents?: number;\r\n // the total adjustments from adjustmentLineItems exlusive of vat\r\n nonCommissionAdjustmentsInCents?: number;\r\n // VAT on adjustments in cents. Needs to be seperate to allow for vat margin scheme\r\n vatOnAdjustmentsInCents?: number;\r\n subtotalGroupTotals: {\r\n [key in SubtotalGroups]: number;\r\n };\r\n taxSubtotalGroupTotals: {\r\n [key in string]: number;\r\n };\r\n // the final total of the invoice after adjustments, commission and tax\r\n finalTotalInCents: number;\r\n}\r\n\r\n// Invoice\r\nexport interface SimplePaymentIn {\r\n paymentId: string;\r\n amountInCents: number;\r\n paymentMethod: PaymentMethod;\r\n reference: string | null;\r\n paidAt: Timestamp;\r\n}\r\n\r\n/**\r\n * Used on invoice to show the payout. Use payout collection for the source of truth\r\n */\r\nexport interface SimplePaymentOut {\r\n payoutId: string;\r\n amountInCents: number;\r\n paymentMethod: PaymentMethod;\r\n reference: string | null;\r\n paidAt: Timestamp;\r\n}\r\n\r\nexport interface Invoice\r\n extends Omit<\r\n Omit<\r\n Omit<Omit<DraftInvoice, \"ledgerAccountTotals\">, \"potentialPayoutsById\">,\r\n \"payoutParams\"\r\n >,\r\n \"status\"\r\n > {\r\n id: string;\r\n invoiceNumber: number;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n marketId: string;\r\n\r\n // a list of the sale IDs that this invoice was created for\r\n // needed for firebase querying\r\n saleIds: string[];\r\n sales: {\r\n // if this was created for a sale or group of sales then the sale id is included\r\n id: string;\r\n // the sale type. like EWES Sale, Store Sale etc,\r\n name?: string;\r\n }[];\r\n\r\n // The transactions that were created on the ledger for this invoice\r\n transactionIds?: string[];\r\n\r\n // issued- valid for seller (not cashed) and buyer ( not paid)\r\n status: \"draft\" | \"issued\" | \"void\" | \"imported\" | \"paid\";\r\n // TODO these aren't yet in place\r\n // | \"uncollectible\" | \"void\" | \"archived\";\r\n\r\n // A simplified copy of the Payment record that would have been created\r\n paymentsInById: {\r\n [paymentId: string]: SimplePaymentIn;\r\n };\r\n\r\n payoutMethod: PayoutMethod | null;\r\n payoutsById: {\r\n [payoutId: string]: SimplePaymentOut;\r\n };\r\n\r\n voidReason?: string;\r\n voidedAt?: Timestamp;\r\n voidedBy?: string;\r\n\r\n // a description of the invoice e.g. 'Invoice for 10 sheep'\r\n description?: string;\r\n\r\n // optional - if a haulier is involved in the sale then the haulier can be added here\r\n // their vehicle reg details and auth number will be pulled from their customer profile\r\n // haulierCustomerId?: string | null;\r\n\r\n // the footer text that appears on the invoice at the bottom. Can be used to add a note to the invoice like ppk or a note to the customer\r\n footnotes?: string[];\r\n\r\n metadata: {\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n\r\n /***\r\n * this is important to add when adding an invoice\r\n * it creates a lock so we only ever get sequential invoice numbers\r\n * The invoice will have this as null until the next invoice is created\r\n */\r\n internalNextInvoiceId: string | null;\r\n\r\n // ID's of the email tasks that have been created for this invoice\r\n emailNotifications?: string[];\r\n\r\n pitchPayLink: string | null;\r\n}\r\nexport interface Printer {\r\n name: string;\r\n id: string;\r\n}\r\n\r\nexport interface InvoiceLineItem {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n\r\n // groups up on the subtotal lines on the invoice\r\n subtotalGroup?: SubtotalGroups | null;\r\n\r\n clientType: ClientType;\r\n\r\n description: string;\r\n\r\n // The sort order of the line item within the invoice\r\n index?: number;\r\n\r\n quantity: number;\r\n // The price of 1 item\r\n impreciseUnitPriceInCents: number;\r\n // helpful later for showing the price per unit\r\n unitOfSale?: UnitOfSale;\r\n unitPriceIncludesVat?: boolean;\r\n\r\n taxRate: TaxRate;\r\n taxAmountInCents: number;\r\n\r\n discountAmountInCents?: number;\r\n\r\n totalAmountInCentsExVat: number; // unitPriceInCents * quantity - discountAmountInCents\r\n\r\n // If this item relates to the sale of item(s)\r\n // handy for drilling down from an invoice to the specific items\r\n saleId?: string;\r\n lotId?: string;\r\n lotProductCode?: string;\r\n superType?: SuperType | null;\r\n // subtype?: ProductSubtype | null;\r\n // If this was a line item for an extra product\r\n productId?: string;\r\n // if this product applies to a lot then this is the lot ID\r\n productRelatedTo?: { lotId: string; saleId: string } | null;\r\n productObfusicate?: boolean;\r\n\r\n // The money for this line item goes to this account\r\n passthroughFundsToCustomerId?: string | null;\r\n\r\n // if this line was created from an adjustment\r\n adjustmentConfig?: AdjustmentsConfiguration;\r\n\r\n metadata: {\r\n [key: string]:\r\n | string\r\n | number\r\n | boolean\r\n | Timestamp\r\n | Media\r\n | { [key: string]: string | number | boolean | Timestamp };\r\n };\r\n}\r\n\r\n// table positions for the tables in invoice PDFs\r\nexport interface TablePosition {\r\n id: InvoiceField | ChequeField | MarketReportHeaders;\r\n title: string;\r\n cellWidth: number; // width of each cell. Each cell is cummulatively added to the x position to build table\r\n halign: \"left\" | \"center\" | \"right\";\r\n}\r\n\r\nexport type WebhookEventName =\r\n | \"market.updated\"\r\n | \"sale.created\"\r\n | \"sale.updated\"\r\n | \"sale.deleted\"\r\n | \"lot.created\"\r\n | \"lot.updated\"\r\n | \"lot.deleted\"\r\n | \"lot.media.created\"\r\n | \"lot.media.deleted\"\r\n | \"invoice.created\"\r\n | \"invoice.updated\"\r\n | \"invoice.deleted\"\r\n | \"payment.created\"\r\n | \"payment.updated\"\r\n | \"payment.deleted\"\r\n | \"payout.created\"\r\n | \"payout.updated\"\r\n | \"payout.deleted\"\r\n // customers\r\n | \"customer.created\"\r\n | \"customer.updated\"\r\n | \"customer.deleted\"\r\n // staff members\r\n | \"member.created\"\r\n | \"member.updated\"\r\n | \"member.deleted\";\r\n\r\nexport const supportedWebhookEvents = [\r\n \"market.updated\",\r\n \"sale.created\",\r\n \"sale.updated\",\r\n \"sale.deleted\",\r\n \"lot.created\",\r\n \"lot.updated\",\r\n \"lot.deleted\",\r\n \"lot.media.created\",\r\n \"lot.media.deleted\",\r\n \"invoice.created\",\r\n \"invoice.updated\",\r\n \"invoice.deleted\",\r\n \"payment.created\",\r\n \"payment.updated\",\r\n \"payment.deleted\",\r\n \"payout.created\",\r\n \"payout.updated\",\r\n \"payout.deleted\",\r\n // customers\r\n \"customer.created\",\r\n \"customer.updated\",\r\n \"customer.deleted\",\r\n // staff members\r\n \"member.created\",\r\n \"member.updated\",\r\n \"member.deleted\",\r\n] as const;\r\n\r\nexport type ObjectType =\r\n | \"market\"\r\n | \"sale\"\r\n | \"lot\"\r\n | \"invoice\"\r\n | \"payment\"\r\n | \"customer\"\r\n | \"member\";\r\n\r\n// The object that is sent to the recevier\r\nexport interface WebhookEvent<T> {\r\n id: string;\r\n createdAt: Timestamp;\r\n trigger: WebhookEventName;\r\n // the market the event relates to\r\n marketId: string;\r\n objectType: ObjectType;\r\n // note object ID not included as sub objects (like lots) need the sale ID too to be referenced. Better to get from the object itself\r\n // objectId: string\r\n data: {\r\n // the object the event relates to\r\n object: T;\r\n // the before / after change on the object\r\n objectBefore?: T;\r\n };\r\n}\r\n\r\nexport type SupportedAttributeTypes =\r\n | \"string\"\r\n | \"number\"\r\n | \"boolean\"\r\n | \"date\"\r\n | \"datetime\"\r\n | \"time\";\r\n\r\nexport interface AttributeDefinition {\r\n // conventions\r\n // prefix with @ for item level attributes\r\n id: string;\r\n name: string;\r\n shortName?: string;\r\n description?: string;\r\n\r\n // An array of {countryCode}/{superType} that this attribute applies to\r\n // e.g. \"GB-NIR/Sheep\" or \"IE/Cattle\"\r\n applyTo: string[];\r\n\r\n // lot => set all items to the same value in the lot\r\n // item => the items can be different values\r\n level: \"item\" | \"lot\";\r\n\r\n // default false\r\n readonly?: boolean;\r\n\r\n // default false. If the attribute can be displayed in the MartEye app / other catalogues\r\n // public?: boolean;\r\n\r\n // if the group is set the attribute will be grouped with other attributes in the same group\r\n lotDetailFlyoutGroup?: string;\r\n\r\n // If the attribute should be set at the checkout phase we assign it to a group\r\n // to appear on the page\r\n buyerCheckoutGroup?: string;\r\n sellerCheckoutGroup?: string;\r\n\r\n // if true, the values for this attribute will be copied over the customer to be used as\r\n // defaults for their next sale. (think CPH or Flock number)\r\n buyerCustomerAttribute?: boolean;\r\n sellerCustomerAttribute?: boolean;\r\n\r\n // If true will hide on the column on the sale sheet\r\n defaultHiddenOnSaleSheet?: boolean;\r\n\r\n // Only if the seller and product code are the same.\r\n // Effective only on the QuickSheet.\r\n prefillableFromPreviousLot?: boolean;\r\n\r\n // If true, isn't shown at all in the lot flyout or the sale sheet.\r\n // Handy for system level attributes.\r\n hidden?: boolean;\r\n\r\n // If true, the attribute will be shown in the seller details panel\r\n // in the quicksheet and in the Rostrum\r\n showInSellerDetailsPanel?: boolean;\r\n\r\n // --- Templates\r\n\r\n // A template used to render the value in the sale sheet (and other places)\r\n displayTemplate?: string;\r\n // for when the level is item, there's more than one value and it's being viewed in a lot context\r\n displayTemplateMultiValue?: string;\r\n\r\n // --- /Templates\r\n\r\n // --- Validation\r\n\r\n type: SupportedAttributeTypes;\r\n\r\n // true if this is required before the price is set.\r\n requiredPreSale: boolean;\r\n\r\n // true if can't checkout without this attribute being valid\r\n // but not needed before the price is set\r\n requiredToCheckout: boolean;\r\n\r\n // validation for number attributes\r\n minValue?: number;\r\n maxValue?: number;\r\n\r\n // validation for string attributes\r\n minLength?: number;\r\n maxLength?: number;\r\n // a regex pattern to match against\r\n regexPattern?: string;\r\n\r\n // validation for date attributes\r\n // we use node-chrono for parsing these\r\n // all expressions are parsed against the sale start date\r\n // examples:\r\n // midnight today: \"2021-01-05T00:00:00.000Z\"\r\n // midnight: \"2021-01-05T00:00:00.000Z\"\r\n // noon: \"2021-01-05T12:00:00.000Z\"\r\n // midnight tomorrow: \"2021-01-06T00:00:00.000Z\"\r\n // yesterday: \"2021-01-04T01:00:00.000Z\"\r\n // next year: \"2022-01-05T01:00:00.000Z\"\r\n // 5 days from now: \"2021-01-10T01:00:00.000Z\"\r\n // 5 days ago: \"2020-12-31T01:00:00.000Z\"\r\n // 60 days ago: \"2020-11-06T01:00:00.000Z\"\r\n // 2 days from now: \"2021-01-07T01:00:00.000Z\"\r\n // 2021-01-01T00:00: \"2021-01-01T00:00:00.000Z\"\r\n minDateExpression?: string;\r\n maxDateExpression?: string;\r\n\r\n // if provided the attribute will only be allowed to be one of these values\r\n allowedValues?: string[];\r\n\r\n // ---/Validation\r\n}\r\n\r\n// Apps Intergations\r\nexport interface StudioAppPartial {\r\n id: string;\r\n name: string;\r\n version: string;\r\n description: string;\r\n icon: string;\r\n parameterConfig: AppParameterConfig[];\r\n parameterValues: {\r\n [key: string]: string | number | boolean | string[];\r\n };\r\n}\r\n\r\nexport type AppParameterConfig = {\r\n id: string;\r\n type: \"string\" | \"number\" | \"boolean\" | \"string[]\" | \"password\";\r\n label: string;\r\n description?: string;\r\n required?: boolean;\r\n defaultValue?: string | number | boolean | string[];\r\n};\r\n","import { supportedWebhookEvents, WebhookEventName } from \"./types\";\n/**\n * Headers used by Studio to identify webhook and action requests\n */\nexport const StudioHeaders = {\n marketId: \"x-studio-market-id\",\n webhookId: \"x-studio-webhook-id\",\n action: \"x-studio-action\",\n apiKey: \"x-studio-key\",\n signature: \"x-studio-signature\",\n};\n\nexport interface StudioManifest {\n id: string; // must be unique\n name: string;\n version: string;\n description: string;\n icon: string;\n author: string;\n\n // action name to url mapping\n actions: {\n name: string;\n url: string;\n }[];\n\n webhooks: {\n url: string;\n triggers: WebhookEventName[];\n }[];\n\n // User configurable settings for the app. Appears in the app settings page.\n parameterConfig: {\n id: string;\n type: \"string\" | \"number\" | \"boolean\" | \"string[]\" | \"password\";\n label: string;\n description?: string;\n required?: boolean;\n defaultValue?: string | number | boolean | string[];\n }[];\n}\n\n/***\n * Creates an app manifest used to describe the app to Studio\n *\n * @param appConfig\n * @returns\n */\nexport function createAppManifest(appConfig: {\n id: string;\n name: string;\n version: string;\n description: string;\n icon: string;\n author: string;\n}) {\n let manifest: StudioManifest = {\n id: appConfig.id,\n name: appConfig.name,\n version: appConfig.version,\n description: appConfig.description,\n icon: appConfig.icon,\n author: appConfig.author,\n webhooks: [],\n parameterConfig: [],\n actions: [],\n };\n\n return {\n addWebhook: (url: string, triggers: WebhookEventName[]) => {\n // Validate the url is a valid url\n try {\n new URL(url);\n } catch (e) {\n throw new Error(`Invalid webhook url. Must be a valid url`);\n }\n\n // Ensure the webhook triggers are allowed\n for (let t of triggers) {\n if (!supportedWebhookEvents.includes(t)) {\n throw new Error(\n `Invalid webhook trigger. Must be one of ${supportedWebhookEvents.join(\n \", \"\n )}`\n );\n }\n }\n\n manifest.webhooks.push({\n url,\n triggers,\n });\n },\n addConfig: (config: {\n id: string;\n type: \"string\" | \"number\" | \"boolean\" | \"string[]\" | \"password\";\n label: string;\n description?: string;\n required?: boolean;\n defaultValue?: string | number | boolean | string[];\n }) => {\n manifest.parameterConfig.push(config);\n },\n addAction: (action: { name: string; url: string }) => {\n manifest.actions.push(action);\n },\n get manifest() {\n // print this and upload to studio\n return manifest;\n },\n };\n}\n"],"names":["create","markets","sales","lots","lotItems","webhooks","actions","HttpClient","Resources"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/net/fetch.ts","../src/net/http.ts","../src/resources/actions.ts","../src/resources/lotItems.ts","../src/resources/lots.ts","../src/resources/markets.ts","../src/resources/sales.ts","../src/resources/webhooks.ts","../src/resources.ts","../src/studio.ts","../src/types.ts","../src/createApp.ts"],"sourcesContent":["export default function getFetch() {\n if (typeof fetch === \"undefined\") {\n throw new Error(\"fetch is not defined. Please use a polyfill.\");\n }\n return fetch;\n}\n","export default function SimpleHttpClient(\n baseUrl: string,\n apiKey: string,\n fetch: any,\n defaultTimeout: number,\n debug: boolean = false\n) {\n async function request<T>(method: string, path: string, body?: any) {\n let controller = new AbortController();\n\n let t = setTimeout(() => {\n controller.abort();\n\n if (debug) {\n console.log(`[SimpleHttpClient] ${method} ${path} timed out`);\n }\n }, defaultTimeout);\n\n let requestInit: any = {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n signal: controller.signal,\n };\n\n if (body) {\n requestInit.body = typeof body === \"string\" ? body : JSON.stringify(body);\n }\n\n if (debug) {\n let info: any = {};\n if (requestInit.headers) {\n info.headers = requestInit.headers;\n }\n if (requestInit.body) {\n info.body = requestInit.body;\n }\n\n console.log(`[SimpleHttpClient] ${method} ${baseUrl}${path}`, info);\n }\n\n let response = await fetch(`${baseUrl}${path}`, requestInit);\n clearTimeout(t);\n\n if (debug) {\n console.log(\n `[SimpleHttpClient] ${method} ${path} response: ${response.status}`\n );\n }\n\n if (response.ok) {\n return response.json() as T;\n }\n\n if (response.status === 404) {\n throw new Error(`${baseUrl}${path} not found`);\n }\n\n throw new Error(\n `Request failed with status ${response.status}: ${await response.text()}}`\n );\n }\n\n return {\n get: async <T>(path: string, queryParams?: any) => {\n let query = queryParams\n ? `?${new URLSearchParams(queryParams).toString()}`\n : \"\";\n return request<T>(\"GET\", `${path}${query}`);\n },\n post: async <T>(path: string, body: any) => {\n return request<T>(\"POST\", path, body);\n },\n delete: async <T>(path: string) => {\n return request<T>(\"DELETE\", path);\n },\n };\n}\n\nexport type HttpClient = ReturnType<typeof SimpleHttpClient>;\n","// Path: studiojs/src/resources/markets.ts\n\nimport { createHmac } from \"crypto\";\nimport { HttpClient } from \"../net/http\";\n\nexport default function create(_: HttpClient) {\n const actions = {\n /***\n * This is used to construct the action from the request body\n *\n * @param body the request body\n * @param signature the signature of the request taken from the header\n * @param endpointSecret the pre-shared secret\n * @returns the action\n */\n constructAction: async (\n bodyAsBuffer: Buffer,\n signature: string,\n endpointSecret: string\n ) => {\n let rawBody = bodyAsBuffer.toString();\n\n let expectedSignature = createHmac(\"sha256\", endpointSecret)\n .update(rawBody)\n .digest(\"hex\");\n\n if (signature !== expectedSignature) {\n console.error(\n `Unable to construct action. Signature mismatch.`,\n signature,\n \"!=\",\n expectedSignature\n );\n throw new Error(`Unable to construct action. Signature mismatch.`);\n }\n\n try {\n return JSON.parse(rawBody);\n } catch (e) {\n throw new Error(`Unable to construct action. ${e}`);\n }\n },\n };\n\n return actions;\n}\n\nexport type Webhooks = ReturnType<typeof create>;\n","import { HttpClient } from \"../net/http\";\nimport { LotItem } from \"../types\";\n\nexport default function create(httpClient: HttpClient) {\n return {\n create: async (\n marketId: string,\n saleId: string,\n lotId: string,\n data: {\n attributes?: Record<string, any>;\n notes?: Array<{\n text: string;\n }>;\n metadata?: Record<string, any>;\n }\n ) => {\n return httpClient.post<LotItem>(\n `/${marketId}/sales/${saleId}/lots/${lotId}/items`,\n data\n );\n },\n update: async (\n marketId: string,\n saleId: string,\n lotId: string,\n itemId: string,\n data: {\n attributes?: Record<string, any>;\n index?: number;\n metadata?: Record<string, any>;\n }\n ) => {\n return httpClient.post<LotItem>(\n `/${marketId}/sales/${saleId}/lots/${lotId}/items/${itemId}`,\n data\n );\n },\n delete: async (\n marketId: string,\n saleId: string,\n lotId: string,\n itemId: string\n ) => {\n return httpClient.delete(\n `/${marketId}/sales/${saleId}/lots/${lotId}/items/${itemId}`\n );\n },\n };\n}\n\nexport type LotItems = ReturnType<typeof create>;\n","import { HttpClient } from \"../net/http\";\nimport { Lot } from \"../types\";\n\nexport default function create(httpClient: HttpClient) {\n return {\n get: async (marketId: string, saleId: string, lotId: string) => {\n return httpClient.get<Lot>(`/${marketId}/sales/${saleId}/lots/${lotId}`);\n },\n list: async (marketId: string, saleId: string) => {\n return httpClient.get<Lot[]>(`/${marketId}/sales/${saleId}/lots`);\n },\n create: async (\n marketId: string,\n saleId: string,\n data: {\n index?: number;\n lotNumber?: string;\n group?: string;\n productCode?: string;\n sellerCustomerId?: string;\n attributes?: Record<string, any>;\n metadata?: Record<string, any>;\n buyerCustomerId?: string;\n unitPriceInCents?: number;\n startedAt?: string;\n endedAt?: string;\n previousLotNumber?: string;\n }\n ) => {\n return httpClient.post<Lot>(`/${marketId}/sales/${saleId}/lots`, data);\n },\n update: async (\n marketId: string,\n saleId: string,\n lotId: string,\n data: {\n productCode?: string;\n attributes?: Record<string, any>;\n sellerCasual?: string | null;\n sellerCustomerId?: string | null;\n lotNumber?: string | null;\n remarks?: string;\n notes?: string;\n unitOfSale?: \"Per KG\" | \"Per Item\" | \"Per Lot\" | \"Per 1000KG\";\n unitPriceInCents?: number;\n buyerCasual?: string | null;\n buyerCustomerId?: string | null;\n startedAt?: string | null;\n endedAt?: string | null;\n saleStatus?: \"Sold\" | \"Unsold\" | \"Rerun\" | \"Resold\" | null;\n metadata?: Record<string, any>;\n }\n ) => {\n return httpClient.post<Lot>(\n `/${marketId}/sales/${saleId}/lots/${lotId}`,\n data\n );\n },\n delete: async (marketId: string, saleId: string, lotId: string) => {\n return httpClient.delete(`/${marketId}/sales/${saleId}/lots/${lotId}`);\n },\n };\n}\n\nexport type Lots = ReturnType<typeof create>;\n","import { HttpClient } from \"../net/http\";\nimport { Market } from \"../types\";\n\nexport default function create(httpClient: HttpClient) {\n const markets = {\n get: async (marketId: string) => {\n return httpClient.get<Market>(`/${marketId}`);\n },\n // update: async (marketId: string, market: Partial<Market>) => {\n // // return httpClient.put<Market>(`/${marketId}`, market);\n // },\n // create: async (market: Market) => {\n // // return httpClient.post<Market>(\"/\", market);\n // },\n // //\n // watch: async (marketId: string, callback: (market: Market) => void) => {\n // // return httpClient.post<Market>(`/${marketId}/watch`);\n // },\n // hint: async (marketId: string, callback: () => void) => {\n // // return httpClient.post<Market>(`/${marketId}/hint`);\n // },\n };\n\n return markets;\n}\n\nexport type Markets = ReturnType<typeof create>;\n","import { HttpClient } from \"../net/http\";\nimport { Sale } from \"../types\";\n\ntype SalesListResponse = {\n start: string;\n end: string;\n sales: Sale[];\n};\n\nexport default function create(httpClient: HttpClient) {\n return {\n get: async (marketId: string, saleId: string) => {\n return httpClient.get<Sale>(`/${marketId}/sales/${saleId}`);\n },\n list: async (\n marketId: string,\n opts: {\n start?: string;\n end?: string;\n }\n ) => {\n return httpClient.get<SalesListResponse>(`/${marketId}/sales`, opts);\n },\n update: async (\n marketId: string,\n saleId: string,\n data: {\n name?: string;\n recurring?: \"Weekly\" | \"Bi-weekly\" | \"Monthly\" | null;\n defaultProductCode?: string;\n attributeDefaults?: Record<string, any>;\n martEyeId?: string | null;\n marteyeSettings?: {\n description?: string;\n image?: string;\n logo?: string;\n type: \"LIVE\" | \"TIMED\";\n location?: string | null;\n descriptionLines?: string[];\n descriptionLink?: string;\n deposit?: number;\n hidePrices?: boolean;\n hideReplay?: boolean;\n labels?: string[];\n tags?: string[];\n details?: Array<{\n markdownBase64: string;\n title: string;\n }>;\n cover?: string;\n primaryColour?: string;\n secondaryColour?: string;\n foregroundColour?: string;\n extensionTime?: number;\n incrementLadder?: Array<{\n max: number;\n increment: number;\n }>;\n hideNav?: boolean;\n signInOverrideLink?: string;\n published?: boolean;\n pin?: boolean;\n cascade?: boolean;\n reportEmail?: string;\n } | null;\n }\n ) => {\n return httpClient.post<Sale>(`/${marketId}/sales/${saleId}`, data);\n },\n };\n}\n\nexport type Sales = ReturnType<typeof create>;\n","// Path: studiojs/src/resources/markets.ts\n\nimport { createHmac } from \"crypto\";\nimport { HttpClient } from \"../net/http\";\nimport { WebhookEvent } from \"../types\";\n\nexport default function create(_: HttpClient) {\n const webhooks = {\n /***\n * This is used to construct the webhook event from the request body\n * @param body the request body\n * @param signature the signature of the request taken from the header\n * @param endpointSecret the pre-shared secret\n * @returns the webhook event\n */\n constructEvent: async <T extends any>(\n bodyAsBuffer: Buffer,\n signature: string | undefined | null,\n endpointSecret: string | undefined | null\n ) => {\n let rawBody = bodyAsBuffer.toString();\n\n if (!endpointSecret) {\n throw new Error(\"Endpoint secret is required\");\n }\n\n if (!signature) {\n throw new Error(\"Signature is required\");\n }\n\n let expectedSignature = createHmac(\"sha256\", endpointSecret)\n .update(rawBody)\n .digest(\"hex\");\n\n if (signature !== expectedSignature) {\n console.error(\n `Unable to construct event. Signature mismatch.`,\n signature,\n \"!=\",\n expectedSignature\n );\n throw new Error(`Unable to construct event. Signature mismatch.`);\n }\n\n try {\n return JSON.parse(rawBody) as WebhookEvent<T>;\n } catch (e) {\n throw new Error(`Unable to construct event. ${e}`);\n }\n },\n };\n\n return webhooks;\n}\n\nexport type Webhooks = ReturnType<typeof create>;\n","import { HttpClient } from \"./net/http\";\n\nimport actions from \"./resources/actions\";\nimport lotItems from \"./resources/lotItems\";\nimport lots from \"./resources/lots\";\nimport markets from \"./resources/markets\";\nimport sales from \"./resources/sales\";\nimport webhooks from \"./resources/webhooks\";\n\nexport default function resources(httpClient: HttpClient) {\n return {\n markets: markets(httpClient),\n sales: sales(httpClient),\n lots: lots(httpClient),\n lotitems: lotItems(httpClient),\n webhooks: webhooks(httpClient),\n actions: actions(httpClient),\n };\n}\n","import getFetch from \"./net/fetch\";\nimport HttpClient from \"./net/http\";\nimport Resources from \"./resources\";\n\nconst BaseUrl = \"https://www.marteyestudio.com/api\";\nconst DefaultTimeout = 10000;\n\nexport function Studio(info: {\n apiKey?: string;\n baseUrl?: string;\n defaultTimeout?: number;\n debug?: boolean;\n}) {\n let apiKeyOrNull = info.apiKey ?? process.env.STUDIO_API_KEY;\n if (!apiKeyOrNull) {\n throw new Error(\"Studio API key is not set\");\n }\n\n let infoWithDefaults = {\n apiKey: apiKeyOrNull,\n baseUrl: info.baseUrl ?? BaseUrl,\n defaultTimeout: info.defaultTimeout ?? DefaultTimeout,\n debug: info.debug ?? false,\n };\n\n let httpClient = HttpClient(\n infoWithDefaults.baseUrl,\n infoWithDefaults.apiKey,\n getFetch(),\n infoWithDefaults.defaultTimeout,\n infoWithDefaults.debug\n );\n\n return {\n ...Resources(httpClient),\n isDebugMode: infoWithDefaults.debug,\n };\n}\n","type Timestamp = string; // ISO 8601\r\n\r\n// dicates vat and commission applicatble to the line item\r\nexport type ClientType = \"Seller\" | \"Buyer\";\r\n\r\nexport type SuperType =\r\n | \"Sheep\"\r\n | \"Goats\"\r\n | \"Cattle\"\r\n | \"Pigs\"\r\n | \"Horses\"\r\n | \"Deer\"\r\n | \"Poultry\"\r\n | \"Machinery\"\r\n | \"Antiques\"\r\n | \"Other\";\r\n\r\nexport const SupportedSuperTypes: SuperType[] = [\r\n \"Sheep\",\r\n \"Goats\",\r\n \"Cattle\",\r\n \"Pigs\",\r\n \"Horses\",\r\n \"Deer\",\r\n \"Poultry\",\r\n \"Machinery\",\r\n \"Antiques\",\r\n \"Other\",\r\n];\r\nexport const LivestockSuperTypes: SuperType[] = [\r\n \"Sheep\",\r\n \"Goats\",\r\n \"Cattle\",\r\n \"Pigs\",\r\n \"Horses\",\r\n \"Deer\",\r\n \"Poultry\",\r\n];\r\n\r\nexport type Currency = \"GBP\" | \"EUR\" | \"USD\";\r\nexport const SupportedCurrencyCodes: Currency[] = [\"GBP\", \"EUR\", \"USD\"];\r\n// ISO 3166-2:GB\r\nexport type SupportedCountryCode =\r\n | \"GB-ENG\"\r\n | \"GB-SCT\"\r\n | \"GB-WLS\"\r\n | \"GB-NIR\"\r\n | \"IE\";\r\nexport type CurrenciesWithGuinea = Currency | \"GUINEA-GBP\";\r\n\r\nexport type UnitOfSale =\r\n | \"Per KG\"\r\n | \"Per Item\" /* aka 'per head'*/\r\n | \"Per Lot\"\r\n | \"Per 1000KG\";\r\nexport const SupportedUnitsOfSale: UnitOfSale[] = [\r\n \"Per KG\",\r\n \"Per Item\",\r\n \"Per Lot\",\r\n \"Per 1000KG\",\r\n];\r\nexport type PaymentMethod =\r\n | \"BACS\"\r\n | \"Cheque\"\r\n | \"BankTransfer\"\r\n | \"Cash\"\r\n | \"Card\"\r\n | \"Credit\"; // contra\r\n\r\nexport type PayoutMethod = \"BACS\" | \"Cheque\" | \"Cash\";\r\n\r\nexport const SupportedPaymentMethods: PaymentMethod[] = [\r\n \"BACS\",\r\n \"Cheque\",\r\n \"BankTransfer\",\r\n \"Cash\",\r\n \"Card\",\r\n \"Credit\",\r\n];\r\n\r\nexport interface Market {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n\r\n name: string;\r\n description: string;\r\n\r\n logo: string;\r\n primaryColour: string;\r\n secondaryColour: string;\r\n\r\n countryCode: SupportedCountryCode;\r\n\r\n address: Address;\r\n\r\n telephone?: string;\r\n vatNumber?: string;\r\n email?: string;\r\n\r\n movementLocationNumbers?: {\r\n number: string;\r\n type: \"CPH\" | \"Herd Number\" | \"Flock Number\" | \"Other\";\r\n // the issuing country that the holding number is valid for\r\n createdAt: Timestamp;\r\n }[];\r\n\r\n // Displayed on the invoice and other documents\r\n paymentInstructions?: string;\r\n\r\n // --/ settings\r\n}\r\n\r\nexport interface SettingsMarketDefaults {\r\n updatedAt: Timestamp;\r\n updatedBy: string | null;\r\n marketId: string;\r\n\r\n name: string;\r\n description: string;\r\n address: Address;\r\n defaultCurrency: Currency;\r\n defaultPayoutPreference: PayoutMethod;\r\n defaultUnitOfSale: UnitOfSale; // the fallback if the product code doesn't have one\r\n\r\n defaultSuperType?: SuperType | null;\r\n\r\n lotDescriptionTemplateMap?: {\r\n default: string | undefined;\r\n [supertype: string]: string | undefined;\r\n };\r\n\r\n rostrumAttributesMap?: {\r\n default: string[] | undefined;\r\n [supertype: string]: string[] | undefined;\r\n };\r\n\r\n // When printing all docs are not selected by default\r\n // You can override that here for whole classes of supertypes\r\n // Add the ID to deselect it when printing. This can be overridden product code\r\n // the most specific setting will be used\r\n selectDocumentIdsMap: {\r\n [supertype: string]: string[];\r\n };\r\n}\r\n\r\nexport interface SettingsProductCodes {\r\n [code: string]: ProductCodeConfiguration;\r\n}\r\n\r\nexport interface SettingsTaxRates {\r\n [id: string]: TaxRate;\r\n}\r\n\r\nexport interface SettingsAdjustmentsConfiguration {\r\n [id: string]: AdjustmentsConfiguration;\r\n}\r\n\r\nexport interface SettingsAccessories {\r\n [id: string]: Accessory;\r\n}\r\n\r\nexport interface SettingsPrinters {\r\n [id: string]: Printer;\r\n}\r\n\r\nexport type DeviceType = \"globeWeigh\" | \"allflexRaceReader\";\r\n\r\nexport interface Accessory {\r\n deviceId: string;\r\n deviceType: DeviceType;\r\n friendlyName: string;\r\n endOfMessagePattern: string;\r\n host: string;\r\n isEnabled: boolean;\r\n port: number;\r\n regex: string;\r\n saleProfileId: string;\r\n timeoutMs: number;\r\n updatedAt: Timestamp;\r\n createdAt: Timestamp;\r\n}\r\n\r\n/**\r\n * @description Configuration for the printer\r\n */\r\nexport interface Printer {\r\n id: string; // our unique id for the printer may include Tray at end if multiple trays\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n\r\n /**\r\n * @description The name of the printer. Its the same as the id\r\n */\r\n name: string; // name of the printer which is used by pdf-to-printer\r\n friendlyName: string; // friendly name e.g. Printer In Office\r\n chequePrinter?: boolean;\r\n /**\r\n * The next cheque number to use when printing a cheque\r\n */\r\n nextChequeNumber?: number;\r\n lastPrintedAt?: Timestamp;\r\n lastPrinterMessage?: string;\r\n}\r\n\r\n// in global studio settings\r\nexport interface SettingsGlobalAttributes {\r\n [id: string]: AttributeDefinition;\r\n}\r\n\r\nexport type AttributeValueType = string | number | boolean | Timestamp | Media;\r\n\r\n/****\r\n * Used to grant a user access to a market.\r\n * Each member of staff should have their own.\r\n */\r\nexport interface MemberSharingConfiguration {\r\n uid: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n\r\n displayName?: string;\r\n photoURL?: string;\r\n\r\n marketId: string;\r\n // only one owner per market.\r\n role: \"Owner\" | \"Admin\" | \"Editor\";\r\n}\r\n\r\nexport interface Sale {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n startsAt: Timestamp;\r\n\r\n closedAt?: Timestamp | null;\r\n\r\n // The owner of the sale\r\n marketId: string;\r\n\r\n // \"Weekly Dairy Sale\" / \"Fat Lambs, Hoggets & Fat Ewes\" etc\r\n name: string;\r\n\r\n recurring?: null | \"Weekly\" | \"Bi-weekly\" | \"Monthly\";\r\n\r\n defaultProductCode: string;\r\n\r\n /**\r\n * Default attributes values for any new lot item\r\n */\r\n attributeDefaults?: {\r\n [attributekey: string]: AttributeValueType;\r\n };\r\n\r\n /**\r\n * the codes that are allowed for the sale\r\n */\r\n availableProductCodes: string[];\r\n\r\n /**\r\n * the supertypes from the product codes. e..g Cattle, Sheep, Pigs etc\r\n */\r\n superTypes: SuperType[];\r\n\r\n // Either the string ID for a known item attibute (begins with an @) or a custom attribute\r\n attributeSet: AttributeDefinition[];\r\n\r\n // Not all attributes are valid for all products\r\n attributeSetByProductCode: {\r\n [code: string]: string[];\r\n };\r\n\r\n // The ID of the group of lots that are currently being sold (for a live sale)\r\n currentLotGroup?: string | null;\r\n // The ID of the group the clerk has queued up next\r\n nextLotGroup?: string | null;\r\n\r\n /**\r\n * Auto queue the next lot when the current lot is sold in rostrum\r\n */\r\n autoQueue?: boolean;\r\n\r\n /**\r\n * The sale profile ID to use for this sale. Which is used to find settings specific devices and printers etc.\r\n */\r\n saleProfileId?: string | null;\r\n\r\n /**\r\n * Show the display board\r\n */\r\n displayBoard?: boolean;\r\n /// folllow on sale ? TBD\r\n\r\n // MartEye Live details\r\n martEyeId?: string | null; // null === not on MartEye\r\n marteyeSettings?: MartEyeTimedSaleSettings | MartEyeLiveSaleSettings | null;\r\n}\r\n\r\nexport interface MartEyeLiveSaleSettings {\r\n description?: string;\r\n image?: string;\r\n logo?: string;\r\n type: \"LIVE\";\r\n\r\n // If you want to oveeride the marts name as the location\r\n location?: string | null;\r\n\r\n // Optional free text used in the info tab on the catalogue page\r\n descriptionLines?: string[];\r\n // optional link to an external catalogue\r\n descriptionLink?: string;\r\n\r\n deposit?: number;\r\n\r\n // true if prices should be hidden after the sale\r\n hidePrices?: boolean;\r\n\r\n // true if we dont want to show replay videos\r\n hideReplay?: boolean;\r\n\r\n labels?: string[];\r\n tags?: string[];\r\n}\r\n\r\nexport interface MartEyeTimedSaleSettings {\r\n description?: string;\r\n // URL of the image to display on the tile\r\n image?: string;\r\n // An override for the logo on the tile\r\n logo?: string;\r\n type: \"TIMED\";\r\n\r\n /**\r\n * The location of the sale. This could be a physical location Ring 1 / Ring 2 / Farm Address etc\r\n */\r\n location?: string | null;\r\n\r\n // The details to go on the front page\r\n details?: { markdownBase64: string; title: string }[];\r\n\r\n // the url for the cover image\r\n cover?: string;\r\n\r\n // dominant colour used for things like the nav bar\r\n primaryColour?: string;\r\n // used for things like the tab bar\r\n secondaryColour?: string;\r\n // the colour used for text or tabbar indicator\r\n foregroundColour?: string;\r\n\r\n // The number of seconds to extend a lot by when there's a last min bid\r\n extensionTime: number;\r\n\r\n // the increments and break points to go up in\r\n incrementLadder: IncrementLadder;\r\n\r\n // if true remove the nav bar on desktop\r\n hideNav?: boolean;\r\n\r\n // a link to send people to when they click the sign in button\r\n signInOverrideLink?: string;\r\n\r\n // should show on main page\r\n published?: boolean;\r\n\r\n // true if should pin to the top of the list\r\n pin?: boolean;\r\n\r\n // labels to show on the tile. Different to tags\r\n labels?: string[];\r\n\r\n // if provided will request that the user submits a deposit\r\n deposit?: number;\r\n\r\n // If true each lot will only being ending once the one before it has closed\r\n cascade?: boolean;\r\n\r\n // comma seperated people to send the report to\r\n reportEmail?: string;\r\n}\r\n\r\nexport type IncrementLadder = IncrementLadderItem[];\r\n\r\nexport interface IncrementLadderItem {\r\n max: number;\r\n increment: number;\r\n}\r\n\r\nexport interface SaleFromSearch\r\n extends Omit<Omit<Omit<Sale, \"createdAt\">, \"updatedAt\">, \"startsAt\"> {\r\n createdAt: number;\r\n updatedAt: number;\r\n startsAt: number;\r\n}\r\n\r\nexport type LotSaleStatus = \"Sold\" | \"Unsold\" | \"Rerun\" | \"Resold\" | null;\r\n\r\nexport interface Lot {\r\n id: string; // unique for the sale? Could be saleId + lotNumber\r\n saleId: string;\r\n marketId: string;\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n // the item code of the lot. This is used to determine the commission rate and the display board\r\n // a lot can only contain items with the same product code (you can think of it as a product type)\r\n productCode: string;\r\n // / Set by a cloud function\r\n superType?: SuperType;\r\n // subtype?: ProductSubtype;\r\n isLivestock?: boolean;\r\n // \\ Set by a cloud function\r\n\r\n attributes: {\r\n [key: string]: AttributeValueType;\r\n };\r\n\r\n // if present here than the attribute is loading in\r\n // remove to signify it has loaded\r\n loadingAttributes?: {\r\n [attributePath: string]: {\r\n id: string;\r\n // time loading began\r\n startAt: Timestamp;\r\n // the path to the attribute (may be on an item)\r\n path: string;\r\n };\r\n };\r\n\r\n itemMap: {\r\n [itemId: string]: LotItem;\r\n };\r\n\r\n sellerCasual?: string | null;\r\n sellerCustomerId: string | null;\r\n seller?: ShortCustomerDetails;\r\n\r\n lotNumber?: string | null;\r\n // The sort order of the lot within the sale\r\n index: number;\r\n // More than one lot can be sold in the ring at once. This groups the lots. Convention to use the earliest lot number in the group as the group ID\r\n group?: string;\r\n\r\n // Free text description of the lot. Intended to be customer facing.\r\n remarks?: string;\r\n\r\n // free text notes, not customer facing possible not needed.\r\n notes?: string;\r\n\r\n // Sale config\r\n currency: CurrenciesWithGuinea;\r\n\r\n unitOfSale: UnitOfSale;\r\n\r\n // --- Sale record\r\n\r\n unitPriceInCents?: number;\r\n\r\n // This could be any free text that the clerk input on the rostrum. It can be thought of as a note for someone to look up the actual buyer later\r\n buyerCasual?: string | null;\r\n buyerCustomerId: string | null;\r\n buyer?: ShortCustomerDetails | null;\r\n\r\n // The time the lot entered and left the ring\r\n startedAt?: Timestamp;\r\n endedAt?: Timestamp;\r\n\r\n // must be set, the null used to find records that have not been invoiced\r\n sellerInvoiceId: string | null;\r\n sellerInvoiceNumber?: number | undefined | null;\r\n // must be set, used to find records that have not been invoiced\r\n buyerInvoiceId: string | null;\r\n buyerInvoiceNumber?: number | undefined | null;\r\n\r\n // If an invoice is voided, we keep a record of the ID here\r\n voidedSellerInvoiceIds?: string[];\r\n voidedBuyerInvoiceIds?: string[];\r\n\r\n // in the case when a lot is unsold.\r\n // The seller gets and invoice but the buyer does not.\r\n saleStatus?: LotSaleStatus;\r\n // ignore the result of this lot. Likely because rerun or resold\r\n void?: boolean;\r\n // if this lot was created from a rerun or resell, this is the ID of the original lot\r\n originalLot?: string;\r\n\r\n // -- /Sale record\r\n\r\n metadata: {\r\n [key: string]: any;\r\n };\r\n\r\n // These are controlled by a cloud function\r\n generated?: LotGeneratedValues;\r\n\r\n // Issues with a lot can be raised asyncronously and resolved later.\r\n issues?: {\r\n [issueId: string]: LotIssue;\r\n };\r\n\r\n resolvedIssues?: {\r\n [issueId: string]: LotIssue;\r\n };\r\n\r\n /***\r\n * Default values for any new lot item\r\n */\r\n itemAttributeDefaults?: {\r\n [attributekey: string]: AttributeValueType;\r\n };\r\n}\r\n\r\ntype LotIssueCode =\r\n | \"unknown-attribute\" // attribute ID is invalid or not setup for this sale\r\n | \"validation-error\" // serverside validation error\r\n | \"staff-flagged\"; // a staff member has raised an issue with the lot that needs to be resovled\r\n\r\nexport interface LotIssue {\r\n id: string;\r\n // optional. If the issue is specific to an item then this is the ID of the item\r\n itemId?: string | null;\r\n // optional. The path to the parameter that caused the issue\r\n path?: string | null;\r\n code: LotIssueCode;\r\n // The issue description\r\n description: string;\r\n // The issue severity\r\n severity: \"error\" | \"warning\" | \"info\";\r\n createdAt: Timestamp;\r\n // Who created the issue\r\n createdBy: string;\r\n // If there is an approval required for this lo\r\n blockCheckout: boolean;\r\n}\r\n\r\nexport interface LotWithItemsAsArray extends Omit<Lot, \"itemMap\"> {\r\n items: LotItem[];\r\n}\r\n\r\nexport interface LotGeneratedValues {\r\n // The total value of the lot in cents\r\n totalValueInCents?: number | null;\r\n\r\n // a description we can use in the cart and on the invoice\r\n description?: string | null;\r\n\r\n // We carry these through to the invoice as averages\r\n pricePerKiloInCents?: number | null;\r\n averageWeightKg?: number | null;\r\n pricePerItemInCents?: number | null;\r\n\r\n countOfItems?: number | null;\r\n}\r\n\r\n// To save a lookup to the customer document we store a copy of the customer details in the lot taken at the time it was added\r\n// Whilst the customer may change their details later it's actually a useful feature not to go back and update the lot with the change\r\nexport interface ShortCustomerDetails {\r\n // true if the customer record has been found and copied in\r\n // false if the customer could not be found\r\n isSet: boolean;\r\n\r\n id?: string;\r\n copiedInAt?: Timestamp;\r\n accountNumber?: string;\r\n bidderNumber?: number | null;\r\n displayName?: string;\r\n\r\n // unsued on everything but the market\r\n avatar?: string | null;\r\n}\r\n\r\n// note the item does not have it's own document in firestore. It exists inside the Lot\r\nexport interface LotItem {\r\n id: string; // unique ID but it wont be created by firestore\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n index: number;\r\n\r\n attributes: {\r\n [key: string]: AttributeValueType;\r\n };\r\n\r\n notes: {\r\n id: string;\r\n text: string;\r\n createdAt: Timestamp;\r\n }[];\r\n\r\n metadata: {\r\n // Interesting things to add here could be:\r\n // - time the item was scanned in\r\n // - photos of the entry forms\r\n // - links to clips generated\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n}\r\n\r\n/***\r\n * A market may offer other products and services. This is a way to track those.\r\n * They simply create a line item on the invoice\r\n *\r\n * /settings/products\r\n */\r\nexport interface Product {\r\n id: string;\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n marketId: string;\r\n\r\n name: string;\r\n taxRateId: string;\r\n defaultUnitPriceInCents: number;\r\n\r\n unitPriceIncludesVat?: boolean;\r\n\r\n // The type of client this config applies too. If empty applies to all client types\r\n applyToClients: ClientType[];\r\n\r\n // line items with the same code are given a subtotal for the group on the invoice\r\n subtotalGroup?: SubtotalGroups | null | undefined;\r\n\r\n // true if this product supports routing this money to another customer (say a dealer or haulier)\r\n passThroughFundsToAnotherCustomer?: boolean;\r\n\r\n // Is the product enabled\r\n isEnabled?: boolean;\r\n\r\n metadata: {\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n}\r\n\r\n/***\r\n * When a product is added to a cart it becomes a CartProductItem\r\n *\r\n *\r\n * markets/ballymena/carts/{userId}\r\n *\r\n * {id: CartItem}\r\n */\r\nexport interface CartItem {\r\n id: string; // unique ID but it wont be created by firestore\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n marketId: string;\r\n customerId: string;\r\n\r\n // The ID of the product\r\n productId: string;\r\n\r\n clientType: ClientType;\r\n // The quantity of the product\r\n quantity: number;\r\n\r\n // The total price of the product\r\n unitPriceInCents: number;\r\n\r\n // If the product supports routing this money to another customer (say a dealer or haulier)\r\n // then this is the ID of the customer to send the funds to\r\n passthroughFundsToCustomerId?: string | null;\r\n\r\n generated?: {\r\n totalInCents: number;\r\n };\r\n}\r\n\r\n/***\r\n * Items have codes. And those codes are used to apply the correct commission rates, report movements etc.\r\n */\r\nexport interface ProductCodeConfiguration {\r\n // Unique for the market, is the ID for the document\r\n code: string;\r\n\r\n createdAt?: Timestamp;\r\n updatedAt?: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n // Integrations will use this for determining if this item needs to have movements reported etc\r\n superType: SuperType;\r\n\r\n // subtype?: ProductSubtype;\r\n\r\n description: string;\r\n\r\n // Name for the icon to use in the UI\r\n icon?: string;\r\n\r\n // A set of expected attributes needed for the catalogue\r\n // attributes?: string[];\r\n\r\n metadata: {\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n\r\n // -- invoices\r\n // - the following generate line items for the invoice.\r\n // - They can be removed or changed manually by the user\r\n\r\n // id for a TaxRate record\r\n // Users shoudl be able to override this on the invoice later\r\n // e.g. people may have different tax rates if they live in another country\r\n taxRateId: string;\r\n\r\n // groups up on the subtotal lines on the invoice\r\n // leave null if grouping isn't needed\r\n subtotalGroup?: SubtotalGroups | null;\r\n\r\n // extra charges to apply on the invoice (e.g. commission, levies etc)\r\n // IDs for AdjustmentsConfiguration records\r\n adjustmentIds: string[];\r\n\r\n // If the price is inclusive of VAT\r\n // We need to for IE as it is assumed the hammer price includes VAT\r\n // default false\r\n unitPriceIncludesVat?: boolean;\r\n\r\n totalExVatRebatePecentage?: number;\r\n\r\n // These carry over to the lots\r\n defaultCurrency?: CurrenciesWithGuinea; // if empty, defaults to market currency\r\n defaultUnitOfSale: UnitOfSale;\r\n\r\n // if provided, the lot will default to this product code when created\r\n // if the number is within this range\r\n defaultLotRange?: {\r\n min: number;\r\n max: number;\r\n };\r\n\r\n // These are copied over to new lots and lot items when created\r\n // item level attributes are prefixed \"@\"\r\n attributeDefaults?: {\r\n [attributekey: string]: AttributeValueType;\r\n };\r\n\r\n // A handlebars template to use for the description on the invoice\r\n lotDescriptionTemplate?: string;\r\n\r\n // The attributes we want editable on the rostrum active page\r\n rostrumAttributes?: string[];\r\n\r\n // When printing all docs are not selected by default\r\n // You can override that here for lots of this product code\r\n selectDocumentIds?: string[] | null;\r\n}\r\n\r\n/***\r\n * How the products are stored in settings\r\n */\r\nexport interface ProductConfiguration {\r\n [id: string]: Product;\r\n}\r\n\r\n/***\r\n * A market may offer other products and services. This is a way to track those.\r\n * They simply create a line item on the invoice\r\n */\r\nexport interface Product {\r\n id: string;\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n marketId: string;\r\n\r\n name: string;\r\n taxRateId: string;\r\n defaultUnitPriceInCents: number;\r\n\r\n unitPriceIncludesVat?: boolean;\r\n\r\n // The type of client this config applies too. If empty applies to all client types\r\n applyToClients: ClientType[];\r\n\r\n // line items with the same code are given a subtotal for the group on the invoice\r\n subtotalGroup?: SubtotalGroups | null | undefined;\r\n\r\n // true if this product supports routing this money to another customer (say a dealer or haulier)\r\n passThroughFundsToAnotherCustomer?: boolean;\r\n\r\n // if this product relates to a lot then this is the lot ID\r\n // e.g. dealer charge for a lot\r\n relatedTo?: { lotId: string; saleId: string } | null;\r\n\r\n // if true, and a relatedTo is set, then the funds will be added to the lot total on the invoice\r\n obfusicate?: boolean;\r\n\r\n metadata: {\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n}\r\n\r\nexport interface Cart {\r\n updatedAt: Timestamp;\r\n itemsById: {\r\n [itemId: string]: CartItem;\r\n };\r\n}\r\n\r\nexport interface EmailWrapper {\r\n email: string;\r\n isVerified: boolean;\r\n createdAt: Timestamp;\r\n}\r\n\r\nexport interface PhoneNumberWrapper {\r\n phoneNumber: string;\r\n isVerified: boolean;\r\n createdAt: Timestamp;\r\n}\r\n\r\nexport interface AddressWrapper {\r\n address: Address;\r\n createdAt: Timestamp;\r\n updatedAt?: Timestamp;\r\n updatedBy?: string | null;\r\n}\r\n\r\nexport interface FarmAssurances {\r\n createdAt: Timestamp;\r\n updatedAt?: Timestamp;\r\n updatedBy?: string | null;\r\n memberReference: string;\r\n expiryDate: Timestamp;\r\n\r\n // TODO need the full list of scopes that Red Tractor use\r\n scope?: \"Beef\" | \"Dairy\" | \"Pork\" | \"Sheep\" | \"Other\";\r\n}\r\n\r\nexport type BankDetails = {\r\n accountName?: string; // Optional used to over ride the name of the account holder\r\n} & (\r\n | { accountNumber: string; sortCode: string; IBAN?: never } // Either accountNumber and sortCode without IBAN\r\n | { IBAN: string; accountNumber?: never; sortCode?: never }\r\n); // Or just IBAN without accountNumber and sortCode\r\n\r\n/**\r\n * Used to store the bank details for a market\r\n */\r\nexport type MarketBankDetails = {\r\n name: string; // The bank account owner\r\n bankId: string; // virgin/hsbc etc\r\n address: Address;\r\n} & (\r\n | { accountNumber: string; sortCode: string; IBAN?: never } // Either accountNumber and sortCode without IBAN\r\n | { IBAN: string; accountNumber?: never; sortCode?: never }\r\n); // Or just IBAN without accountNumber and sortCode\r\n\r\nexport interface Customer {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n\r\n updatedBy?: string | null;\r\n\r\n // The market this customer belongs to\r\n marketId: string;\r\n\r\n // Every market has one customer to represent themselves. If this it true this record is that account.\r\n // Another way to tell is that the ID for this document will be identical to the market ID\r\n isMarketAccount?: boolean;\r\n\r\n // The user's \"account\" with the market. Useful for quick look up + showing on invoices\r\n accountNumber?: string;\r\n // A unique number that can be used to identify the customer.\r\n // Possible that it's reset as soon as after each sale\r\n bidderNumber?: number | null;\r\n\r\n firstName?: string | null;\r\n lastName?: string | null;\r\n\r\n tradingName?: string | null;\r\n\r\n email?: EmailWrapper;\r\n phoneNumber?: PhoneNumberWrapper;\r\n otherPhoneNumbers?: PhoneNumberWrapper[];\r\n\r\n address: AddressWrapper;\r\n otherAddresses: {\r\n [addressId: string]: AddressWrapper;\r\n };\r\n\r\n photoURL?: string | null;\r\n\r\n payoutPreference?: PayoutMethod;\r\n bankDetails?: BankDetails;\r\n\r\n // Attributes to add to the lot when the customer is the seller/buyer\r\n // Here we have an array of attribute values. The most latest used is added to the\r\n // 0 position in the array. The other values could be shown in a dropdown for the user to select\r\n attributeDefaultsBuyer?: {\r\n [attributekey: string]: AttributeValueType[];\r\n };\r\n attributeDefaultsSeller?: {\r\n [attributekey: string]: AttributeValueType[];\r\n };\r\n\r\n // If true any debt on the account will be paid down first before paying out out a credit balance (cheque/BACS etc)\r\n // defaults to true. Some markets call this \"contra\"\r\n preferSettleDebtsFirst?: boolean;\r\n\r\n // People may or may not have VAT numbers. This will affect the tax calculation on their bill.\r\n // the VAT number is used to determine the country and has prefix GB, IE, DE etc. for specific countries\r\n vatNumber?: string;\r\n\r\n metadata: {\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n\r\n // If at any point this customer has bought or sold items in the market\r\n lastItemPurchaseDate?: Timestamp;\r\n lastItemSaleDate?: Timestamp;\r\n hasPurchasedItems?: boolean;\r\n hasSoldItems?: boolean;\r\n\r\n // Notes\r\n notes?: string;\r\n}\r\n\r\n// All Timestamps are replaced with a number\r\nexport interface CustomerFromSearch\r\n extends Omit<\r\n Customer,\r\n \"createdAt\" | \"updatedAt\" | \"lastItemPurchaseDate\" | \"lastItemSaleDate\"\r\n > {\r\n createdAt: number;\r\n updatedAt: number;\r\n\r\n // If at any point this customer has bought or sold items in the market\r\n lastItemPurchaseDate?: number;\r\n lastItemSaleDate?: number;\r\n}\r\n\r\nexport interface Address {\r\n id: string;\r\n nickname?: string;\r\n company?: string;\r\n firstName?: string;\r\n lastName?: string;\r\n address1: string;\r\n address2?: string;\r\n city: string;\r\n province?: string;\r\n zip: string;\r\n // ISO Country Code. Must include the sub-region if applicable (e.g. GB-ENG, GB-WLS, GB-NIR, GB-SCT)\r\n // this is the part that is needed for calculating tax on the invoice\r\n country: string;\r\n}\r\n\r\ninterface ImageThumbnail {\r\n url: string;\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface Media {\r\n id: string;\r\n\r\n url: string;\r\n type: \"image/jpeg\" | \"image/png\" | \"video/mp4\" | \"application/pdf\";\r\n filename: string;\r\n thumbnails?: {\r\n small?: ImageThumbnail;\r\n medium?: ImageThumbnail;\r\n large?: ImageThumbnail;\r\n };\r\n}\r\n\r\n//// --- Report Headers --- ////\r\n\r\nexport type MarketReportHeaders =\r\n | \"grossServices\"\r\n | \"vatOnServices\"\r\n | \"grossGoods\"\r\n | \"vatOnGoods\"\r\n | \"netTotal\"\r\n | \"contra\";\r\n\r\n// --- Invoices ---\r\n/**\r\n * Content types which will denote the position of the data on the invoice wihth out with a cheque\r\n */\r\n\r\n// a type used to define the position of the fields on the cheque\r\nexport type FieldPositions = {\r\n id: ChequeField | InvoiceField;\r\n x: number;\r\n y: number;\r\n};\r\n\r\nexport type InvoiceField =\r\n | \"invoiceNumber\"\r\n | \"invoiceDate\"\r\n | \"description\"\r\n | \"lotNumber\"\r\n | \"quantity\"\r\n | \"weight\"\r\n | \"unitPrice\"\r\n | \"grossLineTotal\"\r\n | \"accountRef\"\r\n | \"accountName\"\r\n | \"businessAddress\"\r\n | \"customerAddress\"\r\n | \"lineItemsStartLine\" // the line that table items start at\r\n | \"footerBoundaryLine\" // this marks the line of the cheque break if used\r\n | \"vatNumber\"\r\n | \"saleName\"\r\n | \"subTotal\" // the column of subtotals e.g. vat, livestock etc\r\n | \"subTotalTable\" // the table of subtotals e.g. vat, livestock etc\";\r\n | \"tagList\"\r\n | \"tagNumber\";\r\n\r\n// a list of fields that can be used to generate a cheque\r\nexport type ChequeField =\r\n | \"chequeDate\"\r\n | \"chequeNumber\"\r\n | \"payee\"\r\n | \"amount\"\r\n | \"amountInWords\"\r\n | \"hunderdsOfThousands\"\r\n | \"tensOfThousands\"\r\n | \"thousands\"\r\n | \"hundreds\"\r\n | \"tens\"\r\n | \"units\";\r\n\r\nexport type SubtotalGroups = \"Commission\" | string;\r\n\r\nexport type AdjustmentTotalTarget =\r\n | \"Per Invoice\"\r\n | \"Total - finalTotalInCents\"\r\n | \"Total - lotTotalLessCommissionInCentsExVat\";\r\n\r\nexport type AdjustmentTarget =\r\n | UnitOfSale\r\n // Apply after the totals have been calculated but before any other total adjustments\r\n | AdjustmentTotalTarget;\r\n\r\n/***\r\n * Commission is added as a line item. Can also be used for levies etc\r\n */\r\nexport interface AdjustmentsConfiguration {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n // a friendly name for the adjustment to be used in the UI\r\n name?: string | null;\r\n\r\n // // How the item appears on the invoice\r\n description?: string | null;\r\n\r\n // The type of client this config applies too. If empty applies to all client types\r\n applyToClients: ClientType[];\r\n\r\n // line items with the same code are given a subtotal for the group on the invoice\r\n subtotalGroup?: SubtotalGroups | null | undefined;\r\n\r\n // this dictates how the money is moved through the ledger\r\n // commission is an income for the market\r\n // a levy would be a \"liability\" as becomes a liability to be paid off later as an expense\r\n // \"vat-rebate\" will (eventually) move the money back into the VAT account\r\n type: \"commission\" | \"levy\" | \"vat-rebate\";\r\n\r\n // Selects where this commission config applies\r\n filter?: {\r\n // apply only to item with this currency\r\n currency?: CurrenciesWithGuinea | null;\r\n\r\n // Apply only between the min and max quantity range (inclusive).\r\n quantity?: {\r\n // default zero\r\n min?: number;\r\n // default Infinity\r\n max?: number;\r\n } | null;\r\n\r\n // Apply only between a min and max per item price\r\n unitPrice?: {\r\n // default zero\r\n minInCents?: number;\r\n // default Infinity\r\n maxInCents?: number;\r\n } | null;\r\n\r\n totalPrice?: {\r\n // default zero\r\n minInCents?: number;\r\n // default Infinity\r\n maxInCents?: number;\r\n } | null;\r\n\r\n // set true to apply this adjustment if a customer is vat registered in any tax region\r\n // false to apply if they are not vat registered\r\n // leave undefined or null to apply to all customers\r\n customerIsVATRegistered?: boolean | null;\r\n // set true to apply this adjustment if the customer is in the same tax region as the market\r\n // false to apply if they are not in the same tax region\r\n // leave undefined or null to apply to all customers\r\n customerWithinTaxRegion?: boolean | null;\r\n\r\n // Will apply if a lot or any items has the attribute key / value pair\r\n // e.g. \"onlineBuyer\" : true\r\n // note we only allow the simple attribute values\r\n attribute?: {\r\n key: string;\r\n // use null to filter for null or undefined values\r\n value: string | number | boolean | null;\r\n } | null;\r\n };\r\n\r\n // The ID of the tax rate that is applied to this adjustment\r\n taxRateId: string;\r\n\r\n adjustment: Adjustment & { target: AdjustmentTarget };\r\n}\r\n\r\ninterface Adjustment {\r\n percentage?: {\r\n // A value between 0-1.\r\n value?: number;\r\n // A minimum value the commision can be\r\n floorInCents?: number;\r\n // A cap for the heighest value a commision can be\r\n ceilingInCents?: number;\r\n } | null;\r\n\r\n // A single amount that is added if the filter applies.\r\n // Could be used for entry fees but likely need to seperate out the entry fee from the commission\r\n fixedAmountInCents?: number | null;\r\n}\r\n\r\nexport interface LineItemAdjustmentConfiguration\r\n extends AdjustmentsConfiguration {\r\n adjustment: Adjustment & { target: UnitOfSale };\r\n}\r\n\r\n// specifically for targeting invoice totals\r\nexport interface InvoiceTotalAdjustmentConfiguration\r\n extends AdjustmentsConfiguration {\r\n adjustment: Adjustment & { target: AdjustmentTotalTarget };\r\n}\r\n\r\n/***\r\n * Tax config is used to generate the invoice but the user can still edit the invoice, overriding the final values.\r\n */\r\nexport interface TaxRate {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n marketId: string;\r\n\r\n // description of the tax shown on the invoice\r\n description: string;\r\n\r\n // line items with the same code are given a subtotal for the group on the invoice\r\n // e.g. \"Tax on Services\" or \"VAT\"\r\n taxSubtotalGroup?: string | null;\r\n\r\n // A value between 0-1. This is the tax rate that will be applied\r\n percentage: number;\r\n\r\n // If true then this tax rate will override others if\r\n // customerIsVATRegistered === true\r\n // customerWithinTaxRegion === false\r\n //\r\n // (see the createDraftInvoice function)\r\n // There can be only one export tax rate. Validate in the UI.\r\n isExportTaxRate?: boolean;\r\n}\r\n\r\n// A payment into the market\r\nexport interface Payment {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string;\r\n\r\n transactionDate: Timestamp;\r\n\r\n marketId: string;\r\n // the customer who made the payment\r\n customerId: string;\r\n method: PaymentMethod;\r\n\r\n // note currency is always assumed to be the market currency\r\n amountInCents: number;\r\n // Should be what will appear on the mart's bank statement\r\n // for a cheque this is the cheque number\r\n // for bacs this is the reference number\r\n // for card this is the transaction reference\r\n // not always present (e.g. cash)\r\n reference: string | null;\r\n\r\n status: \"complete\" | \"void\";\r\n\r\n voidedAt?: Timestamp | null;\r\n voidedBy?: string | null;\r\n voidReason?: string | null;\r\n\r\n // Invoices that this payment went toward\r\n invoiceIds: string[];\r\n\r\n // The transactions that were created on the ledger for this\r\n transactionIds: string[];\r\n}\r\n\r\nexport interface Payout {\r\n id: string;\r\n marketId: string;\r\n\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy: string | null;\r\n customerId: string;\r\n // Credit only allowed for payouts created by the system\r\n method: PayoutMethod | \"Credit\";\r\n amountInCents: number;\r\n\r\n // for BACS these are present\r\n accountName?: string; // usually the customer's name\r\n accountNumber?: string;\r\n sortCode?: string;\r\n\r\n // for cheque these are present\r\n chequeMadePayableTo?: string;\r\n\r\n transactionDate: Timestamp;\r\n reference: string | null;\r\n status: \"pending\" | \"complete\" | \"void\";\r\n notes: string | null;\r\n\r\n completedAt?: Timestamp | null;\r\n completedBy?: string | null;\r\n\r\n voidedAt?: Timestamp | null;\r\n voidedBy?: string | null;\r\n voidReason?: string | null;\r\n\r\n // The transactions that were created on the ledger for this\r\n transactionIds: string[];\r\n\r\n // The invoices paid by this payout\r\n invoiceIds: string[];\r\n}\r\n\r\nexport interface DraftInvoice extends InvoiceTotals {\r\n // the ID is deterministic so saving can be made idempotent\r\n id: string;\r\n\r\n currency: Currency;\r\n\r\n status: \"draft\";\r\n\r\n // the time the invoice was sent\r\n issuedAt?: Timestamp;\r\n\r\n // the identifiers for the lots the invoice is for\r\n lotIdents: { lotId: string; saleId: string }[];\r\n // buyer or seller\r\n clientType: ClientType;\r\n\r\n customerId: string;\r\n customerAccountNumber: string;\r\n\r\n // The name of the customer or trading name to go on the invoice\r\n name: string;\r\n // The customer's address that was used for this invoice.\r\n // The address influences how tax is calculated\r\n address: Address;\r\n email: string | null;\r\n\r\n // the super type of the invoice sheep or cattle etc\r\n superTypes?: SuperType[];\r\n\r\n // The settings around tax used to generate the invoice\r\n customerIsVATRegistered: boolean;\r\n customerWithinTaxRegion: boolean;\r\n\r\n // the line items that make up the invoice\r\n lineItems: InvoiceLineItem[];\r\n // adjustments are added as line items. Can also be used for levies etc\r\n adjustmentLineItems: InvoiceLineItem[];\r\n\r\n // the vat number of the client is required for the invoice if its going for export\r\n vatNumber?: string;\r\n\r\n // the IDs for any extra products that were added onto this invoice\r\n extraProductIds: string[];\r\n\r\n // if a seller, the preferred payout method for this invoice\r\n payoutMethod?: PayoutMethod | null;\r\n payoutParams?: {\r\n // default true, if any debts should be tackled first\r\n settleDebtsFirst: boolean;\r\n\r\n // For BACS\r\n accountName?: string;\r\n accountNumber?: string;\r\n sortCode?: string;\r\n\r\n // For cheque\r\n chequeMadePayableTo?: string;\r\n };\r\n\r\n // The exact payouts wont be accurate until the invoice is finalised\r\n potentialPayoutsById?: {\r\n [payoutId: string]: {\r\n id: string;\r\n amountInCents: number;\r\n paymentMethod: PaymentMethod;\r\n invoice?: {\r\n // included if this payout will pay off an invoice\r\n id: string;\r\n invoiceNumber: number;\r\n fullyPaid: boolean;\r\n };\r\n };\r\n };\r\n\r\n // We may need to collect some info for the lots at checkout (e.g. destination address)\r\n // atrributes here will get set onto the relevant lots once the invoice is created\r\n attributeValues?: {\r\n [attributekey: string]: AttributeValueType;\r\n };\r\n\r\n // The attributes to collect\r\n attributes: AttributeDefinition[];\r\n\r\n // customisable, shown on the invoice\r\n averages?: { label: string; value: number; formattedValue: string }[];\r\n\r\n paymentInstructions?: string | null;\r\n}\r\n\r\nexport interface InvoiceTotals {\r\n //the lot total in cents\r\n lotTotalInCentsExVat: number;\r\n\r\n // the vat on the lot total in cents\r\n vatOnLotTotalInCents: number;\r\n\r\n // this calcluates the total commission from commissionLineItems exlusive of vat\r\n commissionTotalInCents?: number;\r\n // VAT on commission in cents. Needs to be seperate to allow for vat margin scheme\r\n vatOnCommissionInCents?: number;\r\n // the total adjustments from adjustmentLineItems exlusive of vat\r\n nonCommissionAdjustmentsInCents?: number;\r\n // VAT on adjustments in cents. Needs to be seperate to allow for vat margin scheme\r\n vatOnAdjustmentsInCents?: number;\r\n subtotalGroupTotals: {\r\n [key in SubtotalGroups]: number;\r\n };\r\n taxSubtotalGroupTotals: {\r\n [key in string]: number;\r\n };\r\n // the final total of the invoice after adjustments, commission and tax\r\n finalTotalInCents: number;\r\n}\r\n\r\n// Invoice\r\nexport interface SimplePaymentIn {\r\n paymentId: string;\r\n amountInCents: number;\r\n paymentMethod: PaymentMethod;\r\n reference: string | null;\r\n paidAt: Timestamp;\r\n}\r\n\r\n/**\r\n * Used on invoice to show the payout. Use payout collection for the source of truth\r\n */\r\nexport interface SimplePaymentOut {\r\n payoutId: string;\r\n amountInCents: number;\r\n paymentMethod: PaymentMethod;\r\n reference: string | null;\r\n paidAt: Timestamp;\r\n}\r\n\r\nexport interface Invoice\r\n extends Omit<\r\n Omit<\r\n Omit<Omit<DraftInvoice, \"ledgerAccountTotals\">, \"potentialPayoutsById\">,\r\n \"payoutParams\"\r\n >,\r\n \"status\"\r\n > {\r\n id: string;\r\n invoiceNumber: number;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n updatedBy?: string | null;\r\n\r\n marketId: string;\r\n\r\n // a list of the sale IDs that this invoice was created for\r\n // needed for firebase querying\r\n saleIds: string[];\r\n sales: {\r\n // if this was created for a sale or group of sales then the sale id is included\r\n id: string;\r\n // the sale type. like EWES Sale, Store Sale etc,\r\n name?: string;\r\n }[];\r\n\r\n // The transactions that were created on the ledger for this invoice\r\n transactionIds?: string[];\r\n\r\n // issued- valid for seller (not cashed) and buyer ( not paid)\r\n status: \"draft\" | \"issued\" | \"void\" | \"imported\" | \"paid\";\r\n // TODO these aren't yet in place\r\n // | \"uncollectible\" | \"void\" | \"archived\";\r\n\r\n // A simplified copy of the Payment record that would have been created\r\n paymentsInById: {\r\n [paymentId: string]: SimplePaymentIn;\r\n };\r\n\r\n payoutMethod: PayoutMethod | null;\r\n payoutsById: {\r\n [payoutId: string]: SimplePaymentOut;\r\n };\r\n\r\n voidReason?: string;\r\n voidedAt?: Timestamp;\r\n voidedBy?: string;\r\n\r\n // a description of the invoice e.g. 'Invoice for 10 sheep'\r\n description?: string;\r\n\r\n // optional - if a haulier is involved in the sale then the haulier can be added here\r\n // their vehicle reg details and auth number will be pulled from their customer profile\r\n // haulierCustomerId?: string | null;\r\n\r\n // the footer text that appears on the invoice at the bottom. Can be used to add a note to the invoice like ppk or a note to the customer\r\n footnotes?: string[];\r\n\r\n metadata: {\r\n [key: string]: string | number | boolean | Timestamp | Media;\r\n };\r\n\r\n /***\r\n * this is important to add when adding an invoice\r\n * it creates a lock so we only ever get sequential invoice numbers\r\n * The invoice will have this as null until the next invoice is created\r\n */\r\n internalNextInvoiceId: string | null;\r\n\r\n // ID's of the email tasks that have been created for this invoice\r\n emailNotifications?: string[];\r\n\r\n pitchPayLink: string | null;\r\n}\r\nexport interface Printer {\r\n name: string;\r\n id: string;\r\n}\r\n\r\nexport interface InvoiceLineItem {\r\n id: string;\r\n createdAt: Timestamp;\r\n updatedAt: Timestamp;\r\n\r\n // groups up on the subtotal lines on the invoice\r\n subtotalGroup?: SubtotalGroups | null;\r\n\r\n clientType: ClientType;\r\n\r\n description: string;\r\n\r\n // The sort order of the line item within the invoice\r\n index?: number;\r\n\r\n quantity: number;\r\n // The price of 1 item\r\n impreciseUnitPriceInCents: number;\r\n // helpful later for showing the price per unit\r\n unitOfSale?: UnitOfSale;\r\n unitPriceIncludesVat?: boolean;\r\n\r\n taxRate: TaxRate;\r\n taxAmountInCents: number;\r\n\r\n discountAmountInCents?: number;\r\n\r\n totalAmountInCentsExVat: number; // unitPriceInCents * quantity - discountAmountInCents\r\n\r\n // If this item relates to the sale of item(s)\r\n // handy for drilling down from an invoice to the specific items\r\n saleId?: string;\r\n lotId?: string;\r\n lotProductCode?: string;\r\n superType?: SuperType | null;\r\n // subtype?: ProductSubtype | null;\r\n // If this was a line item for an extra product\r\n productId?: string;\r\n // if this product applies to a lot then this is the lot ID\r\n productRelatedTo?: { lotId: string; saleId: string } | null;\r\n productObfusicate?: boolean;\r\n\r\n // The money for this line item goes to this account\r\n passthroughFundsToCustomerId?: string | null;\r\n\r\n // if this line was created from an adjustment\r\n adjustmentConfig?: AdjustmentsConfiguration;\r\n\r\n metadata: {\r\n [key: string]:\r\n | string\r\n | number\r\n | boolean\r\n | Timestamp\r\n | Media\r\n | { [key: string]: string | number | boolean | Timestamp };\r\n };\r\n}\r\n\r\n// table positions for the tables in invoice PDFs\r\nexport interface TablePosition {\r\n id: InvoiceField | ChequeField | MarketReportHeaders;\r\n title: string;\r\n cellWidth: number; // width of each cell. Each cell is cummulatively added to the x position to build table\r\n halign: \"left\" | \"center\" | \"right\";\r\n}\r\n\r\nexport type WebhookEventName =\r\n | \"market.updated\"\r\n | \"sale.created\"\r\n | \"sale.updated\"\r\n | \"sale.deleted\"\r\n | \"lot.created\"\r\n | \"lot.updated\"\r\n | \"lot.deleted\"\r\n | \"lot.media.created\"\r\n | \"lot.media.deleted\"\r\n | \"invoice.created\"\r\n | \"invoice.updated\"\r\n | \"invoice.deleted\"\r\n | \"payment.created\"\r\n | \"payment.updated\"\r\n | \"payment.deleted\"\r\n | \"payout.created\"\r\n | \"payout.updated\"\r\n | \"payout.deleted\"\r\n // customers\r\n | \"customer.created\"\r\n | \"customer.updated\"\r\n | \"customer.deleted\"\r\n // staff members\r\n | \"member.created\"\r\n | \"member.updated\"\r\n | \"member.deleted\";\r\n\r\nexport const supportedWebhookEvents = [\r\n \"market.updated\",\r\n \"sale.created\",\r\n \"sale.updated\",\r\n \"sale.deleted\",\r\n \"lot.created\",\r\n \"lot.updated\",\r\n \"lot.deleted\",\r\n \"lot.media.created\",\r\n \"lot.media.deleted\",\r\n \"invoice.created\",\r\n \"invoice.updated\",\r\n \"invoice.deleted\",\r\n \"payment.created\",\r\n \"payment.updated\",\r\n \"payment.deleted\",\r\n \"payout.created\",\r\n \"payout.updated\",\r\n \"payout.deleted\",\r\n // customers\r\n \"customer.created\",\r\n \"customer.updated\",\r\n \"customer.deleted\",\r\n // staff members\r\n \"member.created\",\r\n \"member.updated\",\r\n \"member.deleted\",\r\n] as const;\r\n\r\nexport type ObjectType =\r\n | \"market\"\r\n | \"sale\"\r\n | \"lot\"\r\n | \"invoice\"\r\n | \"payment\"\r\n | \"customer\"\r\n | \"member\";\r\n\r\n// The object that is sent to the recevier\r\nexport interface WebhookEvent<T> {\r\n id: string;\r\n createdAt: Timestamp;\r\n trigger: WebhookEventName;\r\n // the market the event relates to\r\n marketId: string;\r\n objectType: ObjectType;\r\n // note object ID not included as sub objects (like lots) need the sale ID too to be referenced. Better to get from the object itself\r\n // objectId: string\r\n data: {\r\n // the object the event relates to\r\n object: T;\r\n // the before / after change on the object\r\n objectBefore?: T;\r\n };\r\n}\r\n\r\nexport type SupportedAttributeTypes =\r\n | \"string\"\r\n | \"number\"\r\n | \"boolean\"\r\n | \"date\"\r\n | \"datetime\"\r\n | \"time\";\r\n\r\nexport interface AttributeDefinition {\r\n // conventions\r\n // prefix with @ for item level attributes\r\n id: string;\r\n name: string;\r\n shortName?: string;\r\n description?: string;\r\n\r\n // An array of {countryCode}/{superType} that this attribute applies to\r\n // e.g. \"GB-NIR/Sheep\" or \"IE/Cattle\"\r\n applyTo: string[];\r\n\r\n // lot => set all items to the same value in the lot\r\n // item => the items can be different values\r\n level: \"item\" | \"lot\";\r\n\r\n // default false\r\n readonly?: boolean;\r\n\r\n // default false. If the attribute can be displayed in the MartEye app / other catalogues\r\n // public?: boolean;\r\n\r\n // if the group is set the attribute will be grouped with other attributes in the same group\r\n lotDetailFlyoutGroup?: string;\r\n\r\n // If the attribute should be set at the checkout phase we assign it to a group\r\n // to appear on the page\r\n buyerCheckoutGroup?: string;\r\n sellerCheckoutGroup?: string;\r\n\r\n // if true, the values for this attribute will be copied over the customer to be used as\r\n // defaults for their next sale. (think CPH or Flock number)\r\n buyerCustomerAttribute?: boolean;\r\n sellerCustomerAttribute?: boolean;\r\n\r\n // If true will hide on the column on the sale sheet\r\n defaultHiddenOnSaleSheet?: boolean;\r\n\r\n // Only if the seller and product code are the same.\r\n // Effective only on the QuickSheet.\r\n prefillableFromPreviousLot?: boolean;\r\n\r\n // If true, isn't shown at all in the lot flyout or the sale sheet.\r\n // Handy for system level attributes.\r\n hidden?: boolean;\r\n\r\n // If true, the attribute will be shown in the seller details panel\r\n // in the quicksheet and in the Rostrum\r\n showInSellerDetailsPanel?: boolean;\r\n\r\n // --- Templates\r\n\r\n // A template used to render the value in the sale sheet (and other places)\r\n displayTemplate?: string;\r\n // for when the level is item, there's more than one value and it's being viewed in a lot context\r\n displayTemplateMultiValue?: string;\r\n\r\n // --- /Templates\r\n\r\n // --- Validation\r\n\r\n type: SupportedAttributeTypes;\r\n\r\n // true if this is required before the price is set.\r\n requiredPreSale: boolean;\r\n\r\n // true if can't checkout without this attribute being valid\r\n // but not needed before the price is set\r\n requiredToCheckout: boolean;\r\n\r\n // validation for number attributes\r\n minValue?: number;\r\n maxValue?: number;\r\n\r\n // validation for string attributes\r\n minLength?: number;\r\n maxLength?: number;\r\n // a regex pattern to match against\r\n regexPattern?: string;\r\n\r\n // validation for date attributes\r\n // we use node-chrono for parsing these\r\n // all expressions are parsed against the sale start date\r\n // examples:\r\n // midnight today: \"2021-01-05T00:00:00.000Z\"\r\n // midnight: \"2021-01-05T00:00:00.000Z\"\r\n // noon: \"2021-01-05T12:00:00.000Z\"\r\n // midnight tomorrow: \"2021-01-06T00:00:00.000Z\"\r\n // yesterday: \"2021-01-04T01:00:00.000Z\"\r\n // next year: \"2022-01-05T01:00:00.000Z\"\r\n // 5 days from now: \"2021-01-10T01:00:00.000Z\"\r\n // 5 days ago: \"2020-12-31T01:00:00.000Z\"\r\n // 60 days ago: \"2020-11-06T01:00:00.000Z\"\r\n // 2 days from now: \"2021-01-07T01:00:00.000Z\"\r\n // 2021-01-01T00:00: \"2021-01-01T00:00:00.000Z\"\r\n minDateExpression?: string;\r\n maxDateExpression?: string;\r\n\r\n // if provided the attribute will only be allowed to be one of these values\r\n allowedValues?: string[];\r\n\r\n // ---/Validation\r\n}\r\n\r\n// Apps Intergations\r\nexport interface StudioAppPartial {\r\n id: string;\r\n name: string;\r\n version: string;\r\n description: string;\r\n icon: string;\r\n parameterConfig: AppParameterConfig[];\r\n parameterValues: {\r\n [key: string]: string | number | boolean | string[];\r\n };\r\n}\r\n\r\nexport type AppParameterConfig = {\r\n id: string;\r\n type: \"string\" | \"number\" | \"boolean\" | \"string[]\" | \"password\";\r\n label: string;\r\n description?: string;\r\n required?: boolean;\r\n defaultValue?: string | number | boolean | string[];\r\n};\r\n","import { supportedWebhookEvents, WebhookEventName } from \"./types\";\n/**\n * Headers used by Studio to identify webhook and action requests\n */\nexport const StudioHeaders = {\n marketId: \"x-studio-market-id\",\n webhookId: \"x-studio-webhook-id\",\n action: \"x-studio-action\",\n apiKey: \"x-studio-key\",\n signature: \"x-studio-signature\",\n};\n\nexport interface StudioManifest {\n id: string; // must be unique\n name: string;\n version: string;\n description: string;\n icon: string;\n author: string;\n\n // action name to url mapping\n actions: {\n name: string;\n url: string;\n }[];\n\n webhooks: {\n url: string;\n triggers: WebhookEventName[];\n }[];\n\n // User configurable settings for the app. Appears in the app settings page.\n parameterConfig: {\n id: string;\n type: \"string\" | \"number\" | \"boolean\" | \"string[]\" | \"password\";\n label: string;\n description?: string;\n required?: boolean;\n defaultValue?: string | number | boolean | string[];\n }[];\n}\n\n/***\n * Creates an app manifest used to describe the app to Studio\n *\n * @param appConfig\n * @returns\n */\nexport function createAppManifest(appConfig: {\n id: string;\n name: string;\n version: string;\n description: string;\n icon: string;\n author: string;\n}) {\n let manifest: StudioManifest = {\n id: appConfig.id,\n name: appConfig.name,\n version: appConfig.version,\n description: appConfig.description,\n icon: appConfig.icon,\n author: appConfig.author,\n webhooks: [],\n parameterConfig: [],\n actions: [],\n };\n\n return {\n addWebhook: (url: string, triggers: WebhookEventName[]) => {\n // Validate the url is a valid url\n try {\n new URL(url);\n } catch (e) {\n throw new Error(`Invalid webhook url. Must be a valid url`);\n }\n\n // Ensure the webhook triggers are allowed\n for (let t of triggers) {\n if (!supportedWebhookEvents.includes(t)) {\n throw new Error(\n `Invalid webhook trigger. Must be one of ${supportedWebhookEvents.join(\n \", \"\n )}`\n );\n }\n }\n\n manifest.webhooks.push({\n url,\n triggers,\n });\n },\n addConfig: (config: {\n id: string;\n type: \"string\" | \"number\" | \"boolean\" | \"string[]\" | \"password\";\n label: string;\n description?: string;\n required?: boolean;\n defaultValue?: string | number | boolean | string[];\n }) => {\n manifest.parameterConfig.push(config);\n },\n addAction: (action: { name: string; url: string }) => {\n manifest.actions.push(action);\n },\n get manifest() {\n // print this and upload to studio\n return manifest;\n },\n };\n}\n"],"names":["create","markets","sales","lots","lotItems","webhooks","actions","HttpClient","Resources"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -183,6 +183,12 @@ function create(_) {
183
183
  */
184
184
  constructEvent: async (bodyAsBuffer, signature, endpointSecret) => {
185
185
  let rawBody = bodyAsBuffer.toString();
186
+ if (!endpointSecret) {
187
+ throw new Error("Endpoint secret is required");
188
+ }
189
+ if (!signature) {
190
+ throw new Error("Signature is required");
191
+ }
186
192
  let expectedSignature = crypto.createHmac("sha256", endpointSecret)
187
193
  .update(rawBody)
188
194
  .digest("hex");
@@ -214,14 +220,61 @@ function resources(httpClient) {
214
220
 
215
221
  const BaseUrl = "https://www.marteyestudio.com/api";
216
222
  const DefaultTimeout = 10000;
217
- function Studio(apiKey, baseUrl = BaseUrl, defaultTimeout = DefaultTimeout, debug = false) {
218
- let httpClient = SimpleHttpClient(baseUrl, apiKey, getFetch(), defaultTimeout, debug);
223
+ function Studio(info) {
224
+ var _a, _b, _c, _d;
225
+ let apiKeyOrNull = (_a = info.apiKey) !== null && _a !== void 0 ? _a : process.env.STUDIO_API_KEY;
226
+ if (!apiKeyOrNull) {
227
+ throw new Error("Studio API key is not set");
228
+ }
229
+ let infoWithDefaults = {
230
+ apiKey: apiKeyOrNull,
231
+ baseUrl: (_b = info.baseUrl) !== null && _b !== void 0 ? _b : BaseUrl,
232
+ defaultTimeout: (_c = info.defaultTimeout) !== null && _c !== void 0 ? _c : DefaultTimeout,
233
+ debug: (_d = info.debug) !== null && _d !== void 0 ? _d : false,
234
+ };
235
+ let httpClient = SimpleHttpClient(infoWithDefaults.baseUrl, infoWithDefaults.apiKey, getFetch(), infoWithDefaults.defaultTimeout, infoWithDefaults.debug);
219
236
  return {
220
237
  ...resources(httpClient),
221
- isDebugMode: debug,
238
+ isDebugMode: infoWithDefaults.debug,
222
239
  };
223
240
  }
224
241
 
242
+ const SupportedSuperTypes = [
243
+ "Sheep",
244
+ "Goats",
245
+ "Cattle",
246
+ "Pigs",
247
+ "Horses",
248
+ "Deer",
249
+ "Poultry",
250
+ "Machinery",
251
+ "Antiques",
252
+ "Other",
253
+ ];
254
+ const LivestockSuperTypes = [
255
+ "Sheep",
256
+ "Goats",
257
+ "Cattle",
258
+ "Pigs",
259
+ "Horses",
260
+ "Deer",
261
+ "Poultry",
262
+ ];
263
+ const SupportedCurrencyCodes = ["GBP", "EUR", "USD"];
264
+ const SupportedUnitsOfSale = [
265
+ "Per KG",
266
+ "Per Item",
267
+ "Per Lot",
268
+ "Per 1000KG",
269
+ ];
270
+ const SupportedPaymentMethods = [
271
+ "BACS",
272
+ "Cheque",
273
+ "BankTransfer",
274
+ "Cash",
275
+ "Card",
276
+ "Credit",
277
+ ];
225
278
  const supportedWebhookEvents = [
226
279
  "market.updated",
227
280
  "sale.created",
@@ -251,6 +304,16 @@ const supportedWebhookEvents = [
251
304
  "member.deleted",
252
305
  ];
253
306
 
307
+ var types = /*#__PURE__*/Object.freeze({
308
+ __proto__: null,
309
+ LivestockSuperTypes: LivestockSuperTypes,
310
+ SupportedCurrencyCodes: SupportedCurrencyCodes,
311
+ SupportedPaymentMethods: SupportedPaymentMethods,
312
+ SupportedSuperTypes: SupportedSuperTypes,
313
+ SupportedUnitsOfSale: SupportedUnitsOfSale,
314
+ supportedWebhookEvents: supportedWebhookEvents
315
+ });
316
+
254
317
  /**
255
318
  * Headers used by Studio to identify webhook and action requests
256
319
  */
@@ -314,6 +377,7 @@ function createAppManifest(appConfig) {
314
377
 
315
378
  exports.Studio = Studio;
316
379
  exports.StudioHeaders = StudioHeaders;
380
+ exports.StudioTypes = types;
317
381
  exports.createAppManifest = createAppManifest;
318
382
  exports.default = Studio;
319
383
  //# sourceMappingURL=index.js.map