occasion-sdk
Version:
An SDK library that enables access to Occasion's application, providing a rich DSL for creating and managing bookings.
293 lines (253 loc) • 8.69 kB
JavaScript
Occasion.Modules.push(function(library) {
library.Order = class Order extends library.Base {
static construct(attributes) {
var order = this.includes("currency").build(attributes);
order.sessionIdentifier =
order.sessionIdentifier ||
Math.random()
.toString(36)
.substring(7) +
"-" +
Date.now();
if (order.customer() == null) {
order.buildCustomer({
email: null,
firstName: null,
lastName: null,
zip: null
});
}
var promises = [
new Promise(function(resolve) {
resolve(order);
})
];
if (order.product() != null) {
promises.push(
order
.product()
.questions()
.includes("options")
.perPage(500)
.load()
);
if (!order.product().requiresTimeSlotSelection) {
promises.push(
order
.product()
.timeSlots()
.includes({ product: "merchant" })
.where({ status: "bookable" })
.perPage(500)
.all()
);
}
}
var _this = this;
return Promise.all(promises).then(function(args) {
order = args[0];
var questions = args[1];
var timeSlots = args[2];
if (questions != undefined) questions.inject(order, _this.__constructAnswer);
if (timeSlots != undefined) order.timeSlots().assign(timeSlots, false);
return order;
});
}
// Creates a transaction with a payment method and an amount
//
// @param [PaymentMethod] paymentMethod the payment method to charge
// @param [Number] amount the amount to charge to the payment method
// @return [Transaction] the built transaction representing the charge
charge(paymentMethod, amount) {
return this.transactions().build({
amount: amount,
paymentMethod: paymentMethod
});
}
// Edits a transaction with a given payment method to have a new amount
//
// @param [PaymentMethod] paymentMethod the payment method to search transactions for
// @param [Number] amount the new amount to charge to the payment method
// @return [Transaction] the edited transaction representing the charge
editCharge(paymentMethod, amount) {
var transaction = this.transactions()
.target()
.detect(function(t) {
return t.paymentMethod() == paymentMethod;
});
if (transaction) {
transaction.amount = amount;
}
}
// Removes a transaction for a given payment method
//
// @param [PaymentMethod] paymentMethod the payment method to remove the transaction for
removeCharge(paymentMethod) {
var transaction = this.transactions()
.target()
.detect(function(t) {
return t.paymentMethod() == paymentMethod;
});
if (transaction) {
this.transactions()
.target()
.delete(transaction);
}
}
// @private
// Called by Order.construct, which injects order
// @note Must return order
//
// @param [Occsn.Order] order the order that wants an answer to the question
// @param [Occsn.Question] question the question to construct an answer for
static __constructAnswer(order, question) {
if (question.category != "static") {
let answer = order.answers().build({
question: question
});
switch (question.formControl) {
case "drop_down":
case "option_list":
answer.assignOption(
question
.options()
.target()
.detect(o => {
return o.default;
})
);
break;
case "spin_button":
answer.value = question.min;
break;
}
}
return order;
}
};
library.Order.className = "Order";
library.Order.queryName = "orders";
library.Order.attributes("sessionIdentifier", "status");
library.Order.attributes(
"couponAmount",
"dropInsDiscount",
"giftCardAmount",
"outstandingBalance",
"price",
"priceDueOnInitialOrder",
"quantity",
"subtotal",
"tax",
"taxPercentage",
"total",
"totalDiscount",
{ readOnly: true }
);
library.Order.belongsTo("coupon");
library.Order.belongsTo("currency");
library.Order.belongsTo("customer", { autosave: true, inverseOf: "orders" });
library.Order.belongsTo("merchant");
library.Order.belongsTo("product");
library.Order.hasMany("answers", { autosave: true, inverseOf: "order" });
library.Order.hasMany("attendees", { autosave: true, inverseOf: "order" });
library.Order.hasMany("timeSlots");
library.Order.hasMany("transactions", { autosave: true, inverseOf: "order" });
library.Order.afterRequest(function() {
if (this.product() && !this.product().attendeeQuestions.empty()) {
var diff = this.quantity - this.attendees().size();
if (diff != 0) {
for (var i = 0; i < Math.abs(diff); i++) {
if (diff > 0) {
this.attendees().build();
} else {
this.attendees()
.target()
.pop();
}
}
}
}
ActiveResource.Collection.build([
"couponAmount",
"dropInsDiscount",
"giftCardAmount",
"outstandingBalance",
"price",
"priceDueOnInitialOrder",
"quantity",
"subtotal",
"tax",
"taxPercentage",
"total",
"totalDiscount"
])
.select(attr => this[attr])
.each(attr => {
this[attr] = new Decimal(this[attr]);
});
if (this.outstandingBalance && !this.outstandingBalance.isZero()) {
var giftCardTransactions = this.transactions()
.target()
.select(t => t.paymentMethod() && t.paymentMethod().isA(library.GiftCard));
var remainingBalanceTransaction = this.transactions()
.target()
.detect(t => !(t.paymentMethod() && t.paymentMethod().isA(library.GiftCard)));
if (this.outstandingBalance.isPositive()) {
if (!giftCardTransactions.empty()) {
giftCardTransactions.each(t => {
if (this.outstandingBalance.isZero()) return;
let amount = new Decimal(t.amount);
let giftCardValue = new Decimal(t.paymentMethod().value);
let remainingGiftCardBalance = giftCardValue.minus(amount);
if (remainingGiftCardBalance.isZero()) return;
if (remainingGiftCardBalance.greaterThanOrEqualTo(this.outstandingBalance)) {
amount = amount.plus(this.outstandingBalance);
this.outstandingBalance = new Decimal(0);
} else {
amount = remainingGiftCardBalance;
this.outstandingBalance = this.outstandingBalance.minus(remainingGiftCardBalance);
}
t.amount = amount.toString();
this.transactions()
.target()
.delete(t);
t.__createClone({ cloner: this });
});
}
} else {
if (!giftCardTransactions.empty()) {
ActiveResource.Collection.build(giftCardTransactions.toArray().reverse()).each(t => {
if (this.outstandingBalance.isZero()) return;
let amount = new Decimal(t.amount);
if (amount.greaterThan(this.outstandingBalance.abs())) {
amount = amount.plus(this.outstandingBalance);
this.outstandingBalance = new Decimal(0);
} else {
this.outstandingBalance = this.outstandingBalance.plus(amount);
this.removeCharge(t.paymentMethod());
return;
}
t.amount = amount.toString();
this.transactions()
.target()
.delete(t);
t.__createClone({ cloner: this });
});
}
}
if (!giftCardTransactions.empty()) {
this.giftCardAmount = this.transactions()
.target()
.select(t => t.paymentMethod() && t.paymentMethod().isA(library.GiftCard))
.inject(new Decimal(0), (total, transaction) => total.plus(transaction.amount));
}
if (remainingBalanceTransaction) {
remainingBalanceTransaction.amount = this.outstandingBalance.toString();
this.transactions()
.target()
.delete(remainingBalanceTransaction);
remainingBalanceTransaction.__createClone({ cloner: this });
}
}
});
});