228 lines
6.3 KiB
TypeScript
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);
|
|
}
|
|
}
|