104 lines
3.3 KiB
TypeScript
104 lines
3.3 KiB
TypeScript
import PicnicClient from 'picnic-api'
|
|
import { ApiConfig, Decorator, PriceDecorator, Delivery } from 'picnic-api/lib/types/picnic-api.js'
|
|
import { DateTime } from 'luxon'
|
|
import fs from 'node:fs'
|
|
import { URL } from 'node:url'
|
|
import {jsonOut, csvOut, sum, argv, runCommands} from './util.js'
|
|
|
|
|
|
type QuantityDecorator = {
|
|
type: "QUANTITY",
|
|
quantity: number
|
|
}
|
|
|
|
|
|
const LOGIN_FILE = new URL('login.json', import.meta.url)
|
|
const config: ApiConfig = fs.existsSync(LOGIN_FILE) ? JSON.parse(fs.readFileSync(LOGIN_FILE, 'utf8')) : {}
|
|
|
|
const p = new PicnicClient(config)
|
|
|
|
|
|
function getDecorator(thing: {decorators?: Decorator[]}, name: "QUANTITY", fallback?: number): number
|
|
function getDecorator(thing: {decorators?: Decorator[]}, name: "PRICE", fallback?: number): number
|
|
function getDecorator<R>(thing: {decorators?: Decorator[]}, name: string, fallback?: R): R | undefined {
|
|
if (!thing.decorators) return fallback
|
|
const l = thing.decorators.filter(x => x.type == name)
|
|
if (l.length) {
|
|
switch(name) {
|
|
case "QUANTITY": return l[0].quantity
|
|
case "PRICE": return l[0].display_price
|
|
}
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
function deliveryToCSV(delv: Delivery) {
|
|
const delivered = DateTime.fromISO(delv.slot.window_start).toFormat("yyyy-MM-dd HH:mm")
|
|
for (const order of delv.orders) {
|
|
const ordered = DateTime.fromISO(order.creation_time).toFormat("yyyy-MM-dd HH:mm")
|
|
for (const orderline of order.items) {
|
|
const totalqty = sum(orderline.items.map(x => getDecorator(x, "QUANTITY")))
|
|
// todo orderline decorators
|
|
const real_price = getDecorator(orderline as any, "PRICE", orderline.display_price)
|
|
const display_price = orderline.display_price
|
|
const totalprice = sum(orderline.items.map(x => x.price))
|
|
const promo = real_price / totalprice
|
|
for (const orderarticle of orderline.items) {
|
|
csvOut({
|
|
id: orderarticle.id,
|
|
name: orderarticle.name,
|
|
quantity: getDecorator(orderarticle, "QUANTITY"),
|
|
price: Math.round(orderarticle.price * promo),
|
|
promo: (1 - real_price / orderline.display_price).toFixed(2),
|
|
unit_quantity: orderarticle.unit_quantity,
|
|
ordered, delivered, delivery_id: delv.delivery_id
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const commands = {
|
|
async login(user: string, password: string) {
|
|
await p.login(user, password)
|
|
fs.writeFileSync(LOGIN_FILE, JSON.stringify({
|
|
countryCode: p.countryCode,
|
|
authKey: p.authKey,
|
|
} as ApiConfig))
|
|
},
|
|
async getUserDetails() {
|
|
jsonOut(await p.getUserDetails())
|
|
},
|
|
async deliveries() {
|
|
const deliveries = await p.getDeliveries()
|
|
if (argv.json) {
|
|
jsonOut(deliveries)
|
|
} else {
|
|
for (const delv of deliveries) {
|
|
if (delv.status == 'CANCELLED') continue
|
|
const dt = DateTime.fromISO(delv.delivery_time ? delv.delivery_time.start : delv.slot.window_start)
|
|
csvOut({
|
|
id: delv.delivery_id,
|
|
delivered: dt.toFormat("yyyy-MM-dd HH:mm"),
|
|
status: delv.status,
|
|
price: sum(delv.orders.map(x => x.total_price))
|
|
})
|
|
}
|
|
}
|
|
},
|
|
async delivery(...ids: string[]) {
|
|
for (const deliveryId of ids) {
|
|
const delv = await p.getDelivery(deliveryId)
|
|
if (argv.json) {
|
|
jsonOut(delv)
|
|
} else {
|
|
deliveryToCSV(delv)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeof module === 'undefined' || !module.parent) {
|
|
runCommands(commands)
|
|
}
|