Files
graphql-api-js/src/datasources/order-api.ts
T

228 lines
6.3 KiB
TypeScript

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<Maybe<Address>> {
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<GeneralInput>): Promise<number> {
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<GeneralInput>): Promise<Array<Order>> {
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<Order> {
return this.knex
.select('*')
.from('orders')
.where('id', id)
.first()
.cache(MINUTE)
.then((row) => this.createOrderFromRow(row));
}
async getOrderByExternalId(
klarnaOrderId: string,
paypalTransactionId: string,
): Promise<Order> {
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<any> {
// 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<any> {
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<Array<OrderRow>> {
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<Array<OrderRow>> {
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<GeneralInput>,
): Promise<Array<OrderRow>> {
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);
}
}