-
Notifications
You must be signed in to change notification settings - Fork 10
/
transaction.ts
147 lines (125 loc) · 4.08 KB
/
transaction.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import * as snakecaseKeys from 'snakecase-keys';
import { ArgumentError } from '../errors';
import Account from './account';
import Billing from './billing';
import CreditCard from './credit-card';
import CustomInput from './custom-input';
import Device from './device';
import Email from './email';
import Event from './event';
import Order from './order';
import Payment from './payment';
import Shipping from './shipping';
import ShoppingCartItem from './shopping-cart-item';
interface TransactionProps {
account?: Account;
billing?: Billing;
creditCard?: CreditCard;
customInputs?: CustomInput[];
device: Device;
email?: Email;
event?: Event;
order?: Order;
payment?: Payment;
shipping?: Shipping;
shoppingCart?: ShoppingCartItem[];
}
export default class Transaction {
public account?: Account;
public billing?: Billing;
public creditCard?: CreditCard;
public customInputs?: any;
public device: Device;
public email?: Email;
public event?: Event;
public order?: Order;
public payment?: Payment;
public shipping?: Shipping;
public shoppingCart?: ShoppingCartItem[];
public constructor(transaction: TransactionProps) {
this.ensureTypes(transaction);
// This is done to appease TypeScript - strict
this.device = transaction.device;
Object.assign(this, transaction);
if (transaction.customInputs != null) {
this.customInputs = Object.assign({}, ...transaction.customInputs);
}
}
public toString(): string {
const sanitized = this.sanitizeKeys();
if (sanitized.order != null && sanitized.order.referrerUri) {
sanitized.order.referrerUri = sanitized.order.referrerUri.toString();
}
return JSON.stringify(snakecaseKeys(sanitized));
}
private argumentCheck(property: any, type: any, key: string) {
if (property != null && !(property instanceof type)) {
throw new ArgumentError(
`\`${key}\` needs to be an instance of ${type.name}`
);
}
}
private sanitizeKeys() {
const sanitized = Object.assign({}, this) as any;
if (
sanitized.creditCard != null &&
sanitized.creditCard.last4digits != null
) {
sanitized.creditCard.last_4_digits = this.creditCard!.last4digits;
delete sanitized.creditCard.last4digits;
}
if (sanitized.billing != null && sanitized.billing.address2 != null) {
sanitized.billing.address_2 = this.billing!.address2;
delete sanitized.billing.address2;
}
if (sanitized.shipping != null && sanitized.shipping.address2 != null) {
sanitized.shipping.address_2 = this.shipping!.address2;
delete sanitized.shipping.address2;
}
return sanitized;
}
private checkRegularProps(props: TransactionProps) {
// Excludes device, and array props (customInputs, shoppingCart)
const propTypeMap = ({
account: Account,
billing: Billing,
creditCard: CreditCard,
email: Email,
event: Event,
order: Order,
payment: Payment,
shipping: Shipping,
} as unknown) as typeof props;
const keys = Object.keys(propTypeMap) as Array<keyof typeof props>;
for (const key of keys) {
this.argumentCheck(props[key], propTypeMap[key], key);
}
}
private checkArrayProps(props: TransactionProps) {
if (props.shoppingCart != null) {
for (const [idx, item] of props.shoppingCart.entries()) {
if (!(item instanceof ShoppingCartItem)) {
throw new ArgumentError(
`\`shoppingCart[${idx}]\` needs to be an instance of ShoppingCartItem`
);
}
}
}
if (props.customInputs != null) {
for (const [idx, item] of props.customInputs.entries()) {
if (!(item instanceof CustomInput)) {
throw new ArgumentError(
`\`customInputs[${idx}]\` needs to be an instance of CustomInput`
);
}
}
}
}
private ensureTypes(props: TransactionProps) {
if (!props.device || !(props.device instanceof Device)) {
throw new ArgumentError('`device` needs to be an instance of Device');
}
this.checkRegularProps(props);
this.checkArrayProps(props);
}
}