forked from a/lifeto-shop
227 lines
5.0 KiB
TypeScript
227 lines
5.0 KiB
TypeScript
|
import { LTOApi } from "./api"
|
||
|
import { v4 as uuidv4 } from 'uuid';
|
||
|
import { RefStore } from "../../state/state";
|
||
|
import { debug } from "loglevel";
|
||
|
|
||
|
export const TxnStates = ["PENDING","INFLIGHT","WORKING","ERROR","SUCCESS"] as const
|
||
|
|
||
|
export type TxnState = typeof TxnStates[number]
|
||
|
|
||
|
export interface TxnDetails {
|
||
|
item_uid: string | "galders"
|
||
|
count:number
|
||
|
origin:string
|
||
|
target:string
|
||
|
|
||
|
origin_path:string
|
||
|
target_path:string
|
||
|
}
|
||
|
|
||
|
|
||
|
export abstract class Order {
|
||
|
action_id: string
|
||
|
details?:TxnDetails
|
||
|
created:Date
|
||
|
state: TxnState
|
||
|
constructor(details?:TxnDetails) {
|
||
|
this.state = "PENDING"
|
||
|
this.details = details
|
||
|
this.created = new Date()
|
||
|
this.action_id = uuidv4();
|
||
|
}
|
||
|
|
||
|
mark(t:TxnState) {
|
||
|
this.state = t
|
||
|
}
|
||
|
|
||
|
abstract tick(r:RefStore, api:LTOApi):Promise<any>
|
||
|
abstract status():string
|
||
|
abstract progress():[number, number]
|
||
|
abstract error():string
|
||
|
|
||
|
abstract order_type:OrderType
|
||
|
|
||
|
parse(i:any):Order {
|
||
|
this.action_id = i.action_id
|
||
|
this.details = i.details
|
||
|
this.created = new Date(i.created)
|
||
|
this.state = i.state
|
||
|
return this
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export abstract class BasicOrder extends Order {
|
||
|
stage: number
|
||
|
err?: string
|
||
|
|
||
|
constructor(details:TxnDetails) {
|
||
|
super(details)
|
||
|
this.stage = 0
|
||
|
}
|
||
|
progress():[number,number]{
|
||
|
return [this.stage, 1]
|
||
|
}
|
||
|
status():string {
|
||
|
return this.state
|
||
|
}
|
||
|
error():string {
|
||
|
return this.err ? this.err : ""
|
||
|
}
|
||
|
parse(i:any):BasicOrder {
|
||
|
this.stage = i.stage
|
||
|
this.err = i.err
|
||
|
super.parse(i)
|
||
|
return this
|
||
|
}
|
||
|
}
|
||
|
/// start user defined
|
||
|
|
||
|
export const OrderTypes = ["InvalidOrder","BankItem","InternalXfer"]
|
||
|
export type OrderType = typeof OrderTypes[number]
|
||
|
|
||
|
export class InvalidOrder extends Order{
|
||
|
order_type = "InvalidOrder"
|
||
|
|
||
|
msg:string
|
||
|
constructor(msg: string){
|
||
|
super(undefined)
|
||
|
this.msg = msg
|
||
|
this.mark("ERROR")
|
||
|
}
|
||
|
status():string {
|
||
|
return "ERROR"
|
||
|
}
|
||
|
progress():[number, number] {
|
||
|
return [0,0]
|
||
|
}
|
||
|
error(): string {
|
||
|
return this.msg
|
||
|
}
|
||
|
async tick(r:RefStore, api:LTOApi):Promise<void> {
|
||
|
return
|
||
|
}
|
||
|
parse(i:any):InvalidOrder {
|
||
|
super.parse(i)
|
||
|
this.msg = i.msg
|
||
|
return this
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export interface BasicResponse {
|
||
|
status: number
|
||
|
data: any
|
||
|
msg?: string
|
||
|
}
|
||
|
|
||
|
|
||
|
export interface InternalXferRequest {
|
||
|
item_uid:string
|
||
|
qty:string
|
||
|
account:string
|
||
|
new_char:string
|
||
|
}
|
||
|
|
||
|
export interface InternalXferResponse extends BasicResponse {}
|
||
|
|
||
|
export class InternalXfer extends BasicOrder{
|
||
|
order_type = "InternalXfer"
|
||
|
|
||
|
originalRequest:InternalXferRequest
|
||
|
originalResponse?:InternalXferResponse
|
||
|
constructor(details:TxnDetails) {
|
||
|
super(details)
|
||
|
this.originalRequest = {
|
||
|
item_uid: details.item_uid,
|
||
|
qty: details.count.toString(),
|
||
|
new_char: details.target,
|
||
|
account: details.origin,
|
||
|
}
|
||
|
}
|
||
|
async tick(r:RefStore, api:LTOApi):Promise<void> {
|
||
|
if(this.state !== "PENDING") {
|
||
|
return
|
||
|
}
|
||
|
this.mark("WORKING")
|
||
|
return api.BankAction<InternalXferRequest, InternalXferResponse>("internal-xfer-item",this.originalRequest)
|
||
|
.then((x:InternalXferResponse)=>{
|
||
|
if(x.status == 200){
|
||
|
this.originalResponse = x
|
||
|
this.stage = 1
|
||
|
this.mark("SUCCESS")
|
||
|
const origin_item = r.invs.value.get(this.details?.origin_path!)!.items[this.details?.item_uid!]!
|
||
|
origin_item.item_count = origin_item.item_count - this.details?.count!
|
||
|
r.dirty.value++
|
||
|
}else{
|
||
|
throw x.msg
|
||
|
}
|
||
|
})
|
||
|
.catch((e)=>{
|
||
|
debug("InternalXfer",e)
|
||
|
this.stage = 1
|
||
|
this.err = e
|
||
|
this.mark("ERROR")
|
||
|
})
|
||
|
}
|
||
|
parse(i:any):InternalXfer {
|
||
|
super.parse(i)
|
||
|
this.originalRequest = i.originalRequest
|
||
|
this.originalResponse = i.originalResponse
|
||
|
return this
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export interface BankItemRequest {
|
||
|
item_uid:string
|
||
|
qty:string
|
||
|
account:string
|
||
|
}
|
||
|
|
||
|
export interface BankItemResponse extends BasicResponse {}
|
||
|
|
||
|
export class BankItem extends BasicOrder{
|
||
|
order_type = "BankItem";
|
||
|
|
||
|
originalRequest:BankItemRequest
|
||
|
originalResponse?:BankItemResponse
|
||
|
constructor(details:TxnDetails) {
|
||
|
super(details)
|
||
|
this.originalRequest = {
|
||
|
item_uid: details.item_uid,
|
||
|
qty: details.count.toString(),
|
||
|
account: details.target,
|
||
|
}
|
||
|
}
|
||
|
async tick(r:RefStore, api:LTOApi):Promise<void> {
|
||
|
if(this.state !== "PENDING" ){
|
||
|
return
|
||
|
}
|
||
|
this.mark("WORKING")
|
||
|
return api.BankAction<BankItemRequest, BankItemResponse>("bank-item",this.originalRequest)
|
||
|
.then((x)=>{
|
||
|
debug("BankItem",x)
|
||
|
if(x.status == 200){
|
||
|
this.stage = 1
|
||
|
this.originalResponse = x
|
||
|
this.mark("SUCCESS")
|
||
|
const origin_item = r.invs.value.get(this.details?.origin_path!)!.items[this.details?.item_uid!]!
|
||
|
origin_item.item_count = origin_item.item_count - this.details?.count!
|
||
|
r.dirty.value++
|
||
|
}else {
|
||
|
throw x.msg ? "unknown error" : ""
|
||
|
}
|
||
|
})
|
||
|
.catch((e)=>{
|
||
|
this.stage = 1
|
||
|
this.err = e
|
||
|
this.mark("ERROR")
|
||
|
})
|
||
|
}
|
||
|
|
||
|
parse(i:any):BankItem {
|
||
|
super.parse(i)
|
||
|
this.originalRequest = i.originalRequest
|
||
|
this.originalResponse = i.originalResponse
|
||
|
return this
|
||
|
}
|
||
|
}
|