diff --git a/src/controllers/subscription_manager.ts b/src/controllers/subscription_manager.ts index 40055e2..d919b30 100644 --- a/src/controllers/subscription_manager.ts +++ b/src/controllers/subscription_manager.ts @@ -1,3 +1,4 @@ +import { ORDER } from "#data/data-pools/ORDER.js"; import { generateHMACSignature } from "#middleware/hmac.js"; import { requestBuilder, shopifyHeaderBuilder } from "#shared/requests.js"; import { ScheduledEvent, ShopifyEvent, SubscriptionData, SubscriptorData, Topic } from "./subscriptions.types"; @@ -11,6 +12,7 @@ export class EventScheduler { public eventList: ScheduledEvent[] = [] public activeIntervals: NodeJS.Timeout[] = [] public subscriptionManager: SubscriptionManager + constructor(args: { events?: ScheduledEvent[], subscriptionManager: SubscriptionManager @@ -36,7 +38,7 @@ export class EventScheduler { this.subscriptionManager.poll({ topic: event.topic, - data: { id: 123 } + data: ORDER.randomValue() }) sentMesages++; @@ -84,13 +86,10 @@ export class SubscriptionManager { const subscriptors = this.subscriptions.get(topic) - console.log("[Server] Enviando evento a ", subscriptors) + const body = event.data + const parsedBody = JSON.stringify(body) for (const sub of subscriptors!.subscriptors) { - const body = { - id: 1234 - } - const parsedBody = JSON.stringify(body) const signature = generateHMACSignature(parsedBody, sub.secretkey) const request = requestBuilder({ method: sub.method, diff --git a/src/data/data-pools/ADDRESS.ts b/src/data/data-pools/ADDRESS.ts new file mode 100644 index 0000000..8f1597f --- /dev/null +++ b/src/data/data-pools/ADDRESS.ts @@ -0,0 +1,24 @@ +import { Shopify } from "#data/webhooks/order.js"; +import { FieldPool } from "./pool.type"; + +export const ADDRESS = new FieldPool( + { + id: [9012345, 4455667, 1122334], + customer_id: [7182931, 8293012, 1029384], + first_name: ["Maria", "John", "Yuki"], + last_name: ["García", "Doe", "Tanaka"], + company: ["Tech Solutions S.L.", "Global Corp", null], + address1: ["Calle Mayor 1, 4B", "123 Business Ave", "Shibuya-ku 1-2-3"], + address2: ["Portal A", "Suite 500", null], + city: ["Madrid", "New York", "Tokyo"], + province: ["Madrid", "New York", "Tokyo"], + country: ["Spain", "United States", "Japan"], + zip: ["28001", "10001", "150-0002"], + phone: ["+34600112233", "+15559876543", "+81312345678"], + name: ["Maria García", "John Doe", "Yuki Tanaka"], + province_code: ["M", "NY", "13"], + country_code: ["ES", "US", "JP"], + country_name: ["Spain", "United States", "Japan"], + default: [true, false, false] + } +) diff --git a/src/data/data-pools/CUSTOMER.ts b/src/data/data-pools/CUSTOMER.ts new file mode 100644 index 0000000..cd19a02 --- /dev/null +++ b/src/data/data-pools/CUSTOMER.ts @@ -0,0 +1,46 @@ +import { Shopify } from "#data/webhooks/order.js"; +import { ADDRESS } from "./ADDRESS"; +import { FieldPool } from "./pool.type"; + +export const CUSTOMER = new FieldPool( + { + id: [7182931, 8293012, 1029384], + created_at: ["2023-01-15T10:00:00Z", "2023-11-20T15:30:45Z", "2024-02-05T08:12:00Z"], + updated_at: ["2023-12-01T12:00:00Z", "2024-03-10T09:45:00Z", "2024-05-20T18:20:10Z"], + first_name: ["Maria", "Carlos", "null"], // Ejemplo de nulidad + last_name: ["García", "Smith", "Villanueva"], + state: ["enabled", "disabled", "invited"], + note: ["Cliente VIP", "Prefiere entrega por la tarde", null], + verified_email: [true, false, true], + multipass_identifier: ["ID-99283", "EXT-9102", null], + tax_exempt: [false, true, false], + email_marketing_consent: [ + { + state: "subscribed", + opt_in_level: "confirmed_opt_in", + consent_updated_at: "2024-01-01T10:00:00Z" + }, + { + state: "unsubscribed", + opt_in_level: "single_opt_in", + consent_updated_at: "2023-05-12T14:30:00Z" + }, + null + ], + sms_marketing_consent: [true, false, null], + tags: ["premium, newsletter", "wholesale", ""], + email: ["maria.g@example.com", "carlos_dev@test.io", "info@empresa.es"], + phone: ["+34600112233", "+15559876543", null], + currency: ["EUR", "USD", "MXN"], + tax_exemptions: [ + [], + ["CA_STATUS_CARD", "EXEMPT_CERTIFICATE"], + ["TAX_ID_99"] + ], + admin_graphql_api_id: [ + "gid://shopify/Customer/7182931", + "gid://shopify/Customer/8293012", + "gid://shopify/Customer/1029384" + ], + default_address: [ADDRESS.randomValue()] + }) diff --git a/src/data/data-pools/LINE_ITEM.ts b/src/data/data-pools/LINE_ITEM.ts new file mode 100644 index 0000000..e81735c --- /dev/null +++ b/src/data/data-pools/LINE_ITEM.ts @@ -0,0 +1,68 @@ +import { Shopify } from "#data/webhooks/order.js"; +import { FieldPool } from "./pool.type"; + +/** + * TODO: + * - Muchos de los campos se tendrian que generar a partir de las POOL de los demas + */ + +export const LINE_ITEM = new FieldPool({ + id: [12131415, 22232425, 33343536], + admin_graphql_api_id: [ + "gid://shopify/LineItem/12131415", + "gid://shopify/LineItem/22232425", + "gid://shopify/LineItem/33343536" + ], + attributed_staffs: [[], [{ id: "staff_1", name: "Alex" }], []], + current_quantity: [1, 2, 0], + fulfillable_quantity: [1, 0, 5], + fulfillment_service: ["manual", "amazon-fba", "shipstation"], + fulfillment_status: ["fulfilled", "null", "partial"], + gift_card: [false, false, true], + grams: [500, 1200, 0], + name: ["Camiseta Algodón - L / Azul", "Zapatillas Running - 42", "Tarjeta Regalo Digital"], + price: ["29.99", "85.00", "50.00"], + price_set: [ + { + shop_money: { amount: "29.99", currency_code: "EUR" }, + presentment_money: { amount: "29.99", currency_code: "EUR" } + }, + { + shop_money: { amount: "85.00", currency_code: "USD" }, + presentment_money: { amount: "78.50", currency_code: "EUR" } + }, + { + shop_money: { amount: "50.00", currency_code: "EUR" }, + presentment_money: { amount: "50.00", currency_code: "EUR" } + } + ], + product_exists: [true, true, false], + product_id: [7890123, 8901234, null], + properties: [ + [{ name: "Grabado", value: "Para mi mejor amigo" }], + [], + [{ name: "Envoltorio", value: "Papel reciclado" }, { name: "Prioridad", value: "Alta" }] + ], + quantity: [1, 2, 5], + requires_shipping: [true, true, false], + sku: ["TSHIRT-L-BL", "RUN-SHOE-42", "GIFT-CARD-DIG"], + taxable: [true, true, false], + title: ["Camiseta Algodón", "Zapatillas Running", "Tarjeta Regalo"], + total_discount: ["0.00", "5.00", "10.00"], + total_discount_set: [ + { shop_money: { amount: "0.00", currency_code: "EUR" }, presentment_money: { amount: "0.00", currency_code: "EUR" } }, + { shop_money: { amount: "5.00", currency_code: "EUR" }, presentment_money: { amount: "5.00", currency_code: "EUR" } }, + { shop_money: { amount: "10.00", currency_code: "EUR" }, presentment_money: { amount: "10.00", currency_code: "EUR" } } + ], + variant_id: [454567, 889910, null], + variant_inventory_management: ["shopify", null, "external"], + variant_title: ["L / Azul", "42", null], + vendor: ["Mi Marca S.A.", "Nike", "Apple"], + tax_lines: [ + [{ title: "IVA", price: "6.30", rate: 0.21, price_set: {}, channel_liable: false }], + [{ title: "VAT", price: "17.85", rate: 0.21, price_set: {}, channel_liable: false }], + [] + ], + duties: [[], [], []], + discount_allocations: [[], [], []] +}) diff --git a/src/data/data-pools/ORDER.ts b/src/data/data-pools/ORDER.ts new file mode 100644 index 0000000..a99f5a4 --- /dev/null +++ b/src/data/data-pools/ORDER.ts @@ -0,0 +1,22 @@ +/** + * Opciones para los campos + * TODO: + * - Alguna forma de mapear todos los campos como listas de los originales + */ + +import { ADDRESS } from "#data/data-pools/ADDRESS.js"; +import { CUSTOMER } from "#data/data-pools/CUSTOMER.js"; +import { FieldPool, PoolOf } from "#data/data-pools/pool.type.js"; +import { Shopify } from "../webhooks/order"; + + +export const ORDER = new FieldPool({ + id: [1, 2, 3], + customer: CUSTOMER.randomValue, + shipping_address: ADDRESS.randomValue, + +}) + +export const INVALID_POOL = { + +} diff --git a/src/data/data-pools/PRICE_SET.ts b/src/data/data-pools/PRICE_SET.ts new file mode 100644 index 0000000..d594d88 --- /dev/null +++ b/src/data/data-pools/PRICE_SET.ts @@ -0,0 +1,40 @@ +import { Shopify } from "#data/webhooks/order.js"; +import { FieldPool } from "./pool.type"; + +/** + * shop_money y presentment_money tienen una correlacion que no entiendo. Necesitaria una + * funcion aleatoria nueva + */ + +export const PRICE_SET = new FieldPool({ + shop_money: [ + { + amount: "100.00", + currency_code: "USD" + }, + { + amount: "45.50", + currency_code: "EUR" + }, + { + amount: "12500", + currency_code: "JPY" + } + ], + presentment_money: [ + { + amount: "100.00", + currency_code: "USD" + }, + { + amount: "39.95", + currency_code: "GBP" + }, + { + amount: "12500", + currency_code: "JPY" + } + ] +}) + + diff --git a/src/data/data-pools/pool.test.ts b/src/data/data-pools/pool.test.ts new file mode 100644 index 0000000..d33a32b --- /dev/null +++ b/src/data/data-pools/pool.test.ts @@ -0,0 +1,28 @@ +import { describe, test } from "vitest"; +import { ORDER } from "./ORDER"; +import { CUSTOMER } from "./CUSTOMER"; +import { ADDRESS } from "./ADDRESS"; + + +describe("Test pool", () => { + + test("generacion de costumers", () => { + const costumers = [ + CUSTOMER.randomValue() + ] + console.log("Costumers", costumers) + }) + test("generacion de address", () => { + const costumers = [ + ADDRESS.randomValue() + ] + console.log("ADDRESS", costumers) + }) + test("generacion de 3 order distintos", () => { + const orders = [ + ORDER.randomValue(), + ] + + console.log(orders) + }) +}) diff --git a/src/data/data-pools/pool.type.ts b/src/data/data-pools/pool.type.ts new file mode 100644 index 0000000..35a1055 --- /dev/null +++ b/src/data/data-pools/pool.type.ts @@ -0,0 +1,77 @@ +import { NullablePartial } from "#shared/NullablePartail.js"; + +/** + * Una pool de valores derivada de un tipo existente + * puede ser o bien: + * - Una lista de valores predefinidos + * - Una funcion que devuelve un valor geneerado del mismo tipo que el campo original + */ +export type PoolOf = { + [K in keyof T]: T[K][] | (() => T[K]); +}; + + +/** +*/ +function getRandomOf(pool: PoolOf) { + const mock: NullablePartial = {} + const options = pool + if (options == undefined) throw new Error("El campo no existe en la pool") + for (const optKey in options) { + + const field: T[keyof T][] | (() => T[keyof T]) = options[optKey as keyof typeof options] + if (field == undefined) continue; + + if (typeof field === "function") { + mock[optKey as keyof typeof mock] = field() + } else { + const examplesLen = field.length + if (examplesLen == undefined) continue; + const seleccionado = field[Math.floor(Math.random() * examplesLen)] + mock[optKey as keyof typeof mock] = seleccionado as any // no se como resolver el tipo aqui, se confia que en el ejemplo esté bien + } + } + return mock +} + +/** + * Un FieldPool es un wraper de PoolOf que asocia una funcion + * aleatoria personalizada al tipo de la pool + */ +export class FieldPool { + public pool: PoolOf + public randomValue = () => { + return this.randomFunc(this.pool) + } + + constructor( + pool: PoolOf, + randFunc?: (pool: PoolOf) => T + ) { + this.pool = pool + if (randFunc != undefined) { + this.randomFunc = randFunc + } + } + private randomFunc(pool: PoolOf) { + const mock: NullablePartial = {} + const options = pool + if (options == undefined) throw new Error("El campo no existe en la pool") + for (const optKey in options) { + + const field: T[keyof T][] | (() => T[keyof T]) = options[optKey as keyof typeof options] + if (field == undefined) continue; + + if (typeof field === "function") { + mock[optKey as keyof typeof mock] = field() + } else { + const examplesLen = field.length + if (examplesLen == undefined) continue; + const seleccionado = field[Math.floor(Math.random() * examplesLen)] + mock[optKey as keyof typeof mock] = seleccionado as any // no se como resolver el tipo aqui, se confia que en el ejemplo esté bien + } + } + return mock + } + +} diff --git a/src/data/webhooks/data_pool.ts b/src/data/webhooks/data_pool.ts deleted file mode 100644 index 31cc825..0000000 --- a/src/data/webhooks/data_pool.ts +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Opciones para los campos - * TODO: - * - Alguna forma de mapear todos los campos como listas de los originales - */ - -import { NullablePartial } from "#shared/NullablePartail.js"; -import { Shopify } from "./order"; - -type PoolOf = { - [K in keyof T]: T[K][]; -}; - -type RepoOfPools = { - [K in keyof T]: FieldPool; -} - -export class FieldPool { - public pool: PoolOf - public randomValue() { - return getRandomOf(this.pool) - } - - constructor( - pool: PoolOf - ) { - this.pool = pool - } -} - -/** -*/ -function getRandomOf(pool: PoolOf) { - const mock: NullablePartial = {} - const options = pool - if (options == undefined) throw new Error("El campo no existe en la pool") - for (const optKey in options) { - const field: any[] = options[optKey as keyof typeof options] - if (field == undefined) continue; - const examplesLen = field.length - if (examplesLen == undefined) continue; - const seleccionado = field[Math.floor(Math.random() * examplesLen)] - mock[optKey as keyof typeof mock] = seleccionado as any // no se como resolver el tipo aqui, se confia que en el ejemplo esté bien - } - return mock -} - -const ADDRESS = new FieldPool( - { - id: [9012345, 4455667, 1122334], - customer_id: [7182931, 8293012, 1029384], - first_name: ["Maria", "John", "Yuki"], - last_name: ["García", "Doe", "Tanaka"], - company: ["Tech Solutions S.L.", "Global Corp", null], - address1: ["Calle Mayor 1, 4B", "123 Business Ave", "Shibuya-ku 1-2-3"], - address2: ["Portal A", "Suite 500", null], - city: ["Madrid", "New York", "Tokyo"], - province: ["Madrid", "New York", "Tokyo"], - country: ["Spain", "United States", "Japan"], - zip: ["28001", "10001", "150-0002"], - phone: ["+34600112233", "+15559876543", "+81312345678"], - name: ["Maria García", "John Doe", "Yuki Tanaka"], - province_code: ["M", "NY", "13"], - country_code: ["ES", "US", "JP"], - country_name: ["Spain", "United States", "Japan"], - default: [true, false, false] - } -) - -const CUSTOMER = new FieldPool( - { - id: [7182931, 8293012, 1029384], - created_at: ["2023-01-15T10:00:00Z", "2023-11-20T15:30:45Z", "2024-02-05T08:12:00Z"], - updated_at: ["2023-12-01T12:00:00Z", "2024-03-10T09:45:00Z", "2024-05-20T18:20:10Z"], - first_name: ["Maria", "Carlos", "null"], // Ejemplo de nulidad - last_name: ["García", "Smith", "Villanueva"], - state: ["enabled", "disabled", "invited"], - note: ["Cliente VIP", "Prefiere entrega por la tarde", null], - verified_email: [true, false, true], - multipass_identifier: ["ID-99283", "EXT-9102", null], - tax_exempt: [false, true, false], - email_marketing_consent: [ - { - state: "subscribed", - opt_in_level: "confirmed_opt_in", - consent_updated_at: "2024-01-01T10:00:00Z" - }, - { - state: "unsubscribed", - opt_in_level: "single_opt_in", - consent_updated_at: "2023-05-12T14:30:00Z" - }, - null - ], - sms_marketing_consent: [true, false, null], - tags: ["premium, newsletter", "wholesale", ""], - email: ["maria.g@example.com", "carlos_dev@test.io", "info@empresa.es"], - phone: ["+34600112233", "+15559876543", null], - currency: ["EUR", "USD", "MXN"], - tax_exemptions: [ - [], - ["CA_STATUS_CARD", "EXEMPT_CERTIFICATE"], - ["TAX_ID_99"] - ], - admin_graphql_api_id: [ - "gid://shopify/Customer/7182931", - "gid://shopify/Customer/8293012", - "gid://shopify/Customer/1029384" - ], - default_address: [ADDRESS.randomValue()] - }) - - -export const VALID_POOL: RepoOfPools = { - customer: CUSTOMER, - shipping_address: ADDRESS, -} - -export const INVALID_POOL = { - -} diff --git a/src/data/webhooks/order.d.ts b/src/data/webhooks/order.d.ts index d843c86..a3cbb3f 100644 --- a/src/data/webhooks/order.d.ts +++ b/src/data/webhooks/order.d.ts @@ -19,7 +19,7 @@ export declare namespace Shopify { discount_allocations: unknown[] } - type LineItem = { + type LineItem = NullablePartial<{ id: number, admin_graphql_api_id: string, attributed_staffs: unknown[], @@ -49,9 +49,9 @@ export declare namespace Shopify { tax_lines: TaxLine[], duties: unknown[], discount_allocations: unknown[] - } + }> - export type DiscountAplication = { + type DiscountAplication = { target_type: string, type: string, value: string, @@ -147,7 +147,7 @@ export declare namespace Shopify { user_agent: string, }> - export type PriceSet = { + export type PriceSet = NullablePartial<{ shop_money: { amount: string, currency_code: string @@ -157,7 +157,7 @@ export declare namespace Shopify { currency_code: string } - } + }> // Webhook orders/create export type OrderCreate = Order @@ -252,7 +252,7 @@ export declare namespace Shopify { customer: CustomerData, discount_applications: NullablePartial[], fulfillments: unknown[], - line_items: NullablePartial[], + line_items: LineItem[], payment_terms: unknown, refunds: unknown, shipping_address: Address,