import { BaseSQLDataSource } from './BaseSQLDataSource'; import { camelcase } from 'stringcase'; import { Address, ContactInformation, Order, OrderRow, } from '../types/order-types'; import { DateFilterInput, GeneralInput, Maybe } from '../types/types'; import { convertToPossibleType } from './utils'; import { getProductGroupStringFromString } from '../types/product-types'; const MINUTE = 60; export class OrderAPI extends BaseSQLDataSource { constructor(config) { super(config); } async getAddress(addressId: number): Promise> { const row = await this.knex .select('*') .from('addresses') .where('id', addressId) .first() .cache(MINUTE); return row ? { ...row, /* Change this later to camelCase but also need to change in Pwinty lambda */ firstname: row.firstName, lastname: row.lastName, companyname: row.companyName, recipientName: `${row.firstName} ${row.lastName}`.trim(), stateCountyOrRegion: row.state ? row.state : null, } : null; } getBillingInformation(row): ContactInformation { return { email: row.email, phone: row.phone, addressId: row.billingAddressId, }; } getDeliveryInformation(row): ContactInformation { return { email: row.deliveryEmail, phone: row.deliveryPhone, addressId: row.deliveryAddressId, }; } createOrderFromRow(row: any): Order { row.__resolveType = 'Order'; row.billingInformation = this.getBillingInformation(row); row.deliveryInformation = this.getDeliveryInformation(row); return row; } async getOrdersTotal(input: Maybe): Promise { const res = await this.getOrdersQuery(input) .clone() .count() .first() .cache(MINUTE * 60); return res['count'] as number; // Optimize later to return Promise } async getOrders(input: Maybe): Promise> { let query = this.getOrdersQuery(input).limit(input?.pagination.limit); // TODO: handle offset query = query.orderBy('inserted', 'ASC'); return query .cache(MINUTE) .then((rows) => rows.map((row) => this.createOrderFromRow(row))); } private getOrdersQuery(input: GeneralInput) { let query = this.knex.table('orders'); if (input?.filter?.dates?.from) { query = query.where('inserted', '>=', input.filter.dates.from); } if (input?.filter?.dates?.to) { query = query.where('inserted', '<=', input.filter.dates.to); } return query; } async getOrderById(id: number): Promise { return this.knex .select('*') .from('orders') .where('id', id) .first() .cache(MINUTE) .then((row) => this.createOrderFromRow(row)); } async getOrderByExternalId( klarnaOrderId: string, paypalTransactionId: string, ): Promise { const column = paypalTransactionId ? 'paypal_transaction_id' : 'klarna_order_id'; const value = paypalTransactionId ?? klarnaOrderId; return this.knex .select('*') .from('orders') .where(column, value) .orderBy('id') .first() .cache(MINUTE) .then((row) => { return row ? this.createOrderFromRow(row) : null; }); } async getOrderRowFieldMapping(): Promise { // const fields = await this.knex.select('*').from('order-row_fields'); doesn't work becuase of string case... const fieldsRes = await this.cachedRaw('SELECT * from "order-row_fields"') .cache(MINUTE * 60) .then((data) => data.rows); return fieldsRes.reduce((obj, item) => { obj[item.fieldid] = item.name; return obj; }, {}); } /** * Gets the row details */ async getOrderRowDetailsForRowId(rowId: number): Promise { const details = await this.knex .raw('SELECT * FROM "order-rows_details" WHERE rowid = ?', rowId) .then((data) => data.rows); // Skip empty order rows if (!details.length) { return null; } const fields = await this.getOrderRowFieldMapping(); const orderRow = details.reduce((obj, item) => { const value = convertToPossibleType(item.value); obj[camelcase(fields[item.fieldid])] = value; return obj; }, {}); if ('group' in orderRow) { orderRow['productGroup'] = orderRow['group']; orderRow['group'] = getProductGroupStringFromString(orderRow['group']); } return orderRow; } /** * Takes input from order-rows query and gets the row details */ async getOrderRows(rows: any): Promise> { let orderRows = []; for (let i = 0; i < rows.length; i++) { const rowId = rows[i].rowid; const orderRow = await this.getOrderRowDetailsForRowId(rowId); if (!orderRow) { continue; } // take some data from order-rows results orderRow['id'] = rowId; orderRow['orderId'] = rows[i].orderid; orderRow['inserted'] = rows[i].inserted; orderRows.push(orderRow); } return orderRows; } async getOrderRowsByOrderId(orderId: number): Promise> { const rows = await this.knex .raw('SELECT * FROM "order-rows" WHERE orderid = ?', orderId) .then((data) => data.rows); return this.getOrderRows(rows); } async getOrderRowsByDesignerId( designerId: number, input: Maybe, ): Promise> { const query = /* sql */ ` SELECT orderdetails.*, "order-rows".orderid FROM "order-rows_details" orderdetails JOIN "order-rows" ON "order-rows".rowid = orderdetails.rowid WHERE orderdetails.fieldid = 105 AND orderdetails.value = ? AND orderdetails.inserted >= ? AND orderdetails.inserted <= ? ORDER BY orderdetails.inserted ASC ${input?.pagination.limit ? `LIMIT ${input.pagination.limit}` : ''} `; const from = input?.filter?.dates?.from ? input.filter.dates.from : new Date('2000-01-01'); const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); const to = input?.filter?.dates?.to ? input.filter?.dates.to : tomorrow; // Tomorrow const rows = await this.knex .raw(query, [designerId, this.getSQLDate(from), this.getSQLDate(to)]) .then((data) => data.rows); return this.getOrderRows(rows); } }