Skip to content

Commit

Permalink
feat: Order Amount calculation integration (#4427)
Browse files Browse the repository at this point in the history
  • Loading branch information
iamareebjamal authored Jun 2, 2020
1 parent 8c8d279 commit eeb15a9
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 101 deletions.
108 changes: 68 additions & 40 deletions app/components/public/ticket-list.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { debounce } from '@ember/runloop';
import FormMixin from 'open-event-frontend/mixins/form';
import { inject as service } from '@ember/service';
import { sumBy, merge } from 'lodash-es';
Expand All @@ -10,6 +11,8 @@ export default Component.extend(FormMixin, {

promotionalCodeApplied: false,

orderAmount: null,

isUnverified: computed('session.isAuthenticated', 'authManager.currentUser.isVerified', function() {
return this.session.isAuthenticated
&& !this.authManager.currentUser.isVerified;
Expand All @@ -25,21 +28,31 @@ export default Component.extend(FormMixin, {
}
}),

showTaxIncludedMessage: computed('taxInfo.isTaxIncludedInPrice', function() {
if (this.taxInfo !== null) {
return (this.taxInfo.isTaxIncludedInPrice);
}
return false;
}),

accessCodeTickets : A(),
discountedTickets : A(),

invalidPromotionalCode: false,

tickets: computed(function() {
return this.data.sortBy('position');
tickets: computed('orderAmount', function() {
const ticketMap = {};
if (this.orderAmount) {
this.orderAmount.tickets.forEach(ticket => {
ticketMap[ticket.id] = ticket;
});
}

return this.data.sortBy('position').map(ticket => {
const ticketExtra = ticketMap[ticket.id];

if (ticketExtra) {
ticket.set('subTotal', ticketExtra.sub_total);
ticket.set('discountInfo', ticketExtra.discount);
}

return ticket;
});
}),

hasTicketsInOrder: computed('tickets.@each.orderQuantity', function() {
return sumBy(this.tickets.toArray(),
ticket => (ticket.orderQuantity || 0)
Expand Down Expand Up @@ -68,6 +81,19 @@ export default Component.extend(FormMixin, {
ticket => ((ticket.price || 0) - (ticket.discount || 0)) * (ticket.orderQuantity || 0)
);
}),

orderAmountInput: computed('tickets.@each.price', 'order.tickets.@each.orderQuantity', 'order.discountCode', function() {

return {
tickets: this.order.tickets.toArray().map(ticket => ({
id : ticket.id,
quantity : ticket.orderQuantity,
price : ticket.price
})),
'discount-code': this.order.get('discountCode.id')
};
}),

actions: {
async togglePromotionalCode(queryParam) {
this.toggleProperty('enterPromotionalCode');
Expand All @@ -82,24 +108,16 @@ export default Component.extend(FormMixin, {
this.set('code', null);
this.order.set('accessCode', undefined);
this.order.set('discountCode', undefined);
this.tickets.forEach(ticket => {
ticket.set('discount', null);
});
this.accessCodeTickets.forEach(ticket => {
ticket.set('isHidden', true);
this.tickets.removeObject(ticket);
});
this.discountedTickets.forEach(ticket => {
let taxRate = ticket.get('event.tax.rate');
let ticketPrice = ticket.get('price');
if (taxRate && !this.showTaxIncludedMessage) {
let ticketPriceWithTax = ticketPrice * (1 + taxRate / 100);
ticket.set('ticketPriceWithTax', ticketPriceWithTax);
} else if (taxRate && this.showTaxIncludedMessage) {
let includedTaxAmount = (taxRate * ticketPrice) / (100 + taxRate);
ticket.set('includedTaxAmount', includedTaxAmount);
}
ticket.set('discount', 0);
});
this.accessCodeTickets.clear();
this.discountedTickets.clear();
this.send('updateOrderAmount');
}

}
Expand All @@ -126,22 +144,11 @@ export default Component.extend(FormMixin, {
const discountCode = await this.store.queryRecord('discount-code', { eventIdentifier: this.event.id, code: this.promotionalCode, include: 'event,tickets' });
const discountCodeEvent = await discountCode.event;
if (this.currentEventIdentifier === discountCodeEvent.identifier) {
const discountType = discountCode.type;
const discountValue = discountCode.value;
this.order.set('discountCode', discountCode);
const tickets = await discountCode.tickets;
tickets.forEach(ticket => {
const ticketPrice = ticket.price;
const taxRate = ticket.get('event.tax.rate');
const discount = discountType === 'amount' ? Math.min(ticketPrice, discountValue) : ticketPrice * (discountValue / 100);
const discount = discountCode.type === 'amount' ? Math.min(ticket.price, discountCode.value) : ticket.price * (discountCode.value / 100);
ticket.set('discount', discount);
if (taxRate && !this.showTaxIncludedMessage) {
const ticketPriceWithTax = (ticketPrice - ticket.discount) * (1 + taxRate / 100);
ticket.set('ticketPriceWithTax', ticketPriceWithTax);
} else if (taxRate && this.showTaxIncludedMessage) {
const includedTaxAmount = (taxRate * (ticketPrice - discount)) / (100 + taxRate);
ticket.set('includedTaxAmount', includedTaxAmount);
}
this.discountedTickets.addObject(ticket);
this.set('invalidPromotionalCode', false);
});
Expand All @@ -163,29 +170,50 @@ export default Component.extend(FormMixin, {
this.set('promotionalCodeApplied', true);
this.set('promotionalCode', 'Promotional code applied successfully');
}
this.order.set('amount', this.total);

this.send('updateOrderAmount');
},
updateOrder(ticket, count) {

async updateOrder(ticket, count) {
ticket.set('orderQuantity', count);
this.order.set('amount', this.total);
if (!this.total) {
this.order.set('amount', 0);
}
if (count > 0) {
this.order.tickets.addObject(ticket);
} else {
ticket.set('subTotal', null);
ticket.set('discountInfo', null);
if (this.order.tickets.includes(ticket)) {
this.order.tickets.removeObject(ticket);
}
}

this.send('updateOrderAmount');
},

async updateOrderAmount() {
if (this.shouldDisableOrderButton) {
this.set('orderAmount', null);
return;
}

try {
this.set('orderAmount', await this.loader.post('/orders/calculate-amount', this.orderAmountInput));
this.order.amount = this.orderAmount.total;
} catch (e) {
console.error('Error while calculating order amount', e);
this.notify.error(e.response.errors[0].detail, {
id: 'order-amount-error'
});
}
},

handleKeyPress() {
if (event.code === 'Enter') {
this.send('applyPromotionalCode');
this.set('code', this.promotionalCode);
}
},

onChangeDonation() {
debounce(this, () => this.send('updateOrderAmount'), this.tickets, 250);
}
},
didInsertElement() {
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/currency-symbol.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { paymentCurrencies } from 'open-event-frontend/utils/dictionary/payment'

export function currencySymbol(params) {
const currency = find(paymentCurrencies, ['code', params[0]]);
return currency ? currency.symbol : 'UNKNOWN';
return currency ? currency.symbol : params[0];
}

export default Helper.helper(currencySymbol);
4 changes: 4 additions & 0 deletions app/styles/partials/utils.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@
.mb-8 {
margin-bottom: 2rem;
}

.m-0 {
margin: 0 !important;
}
114 changes: 56 additions & 58 deletions app/templates/components/public/ticket-list.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<thead class="full-width">
<tr>
<th>{{t 'Type'}}</th>
<th class="four wide">{{t 'Sales Ends'}}</th>
<th class="ui three wide single line">{{t 'Ticket Price'}}</th>
<th class="three wide"></th>
<th class="ui four wide single line">{{t 'Price'}}</th>
<th class="one wide">{{t 'Quantity'}}</th>
<th class="ui right aligned two wide">{{t 'Subtotal'}}</th>
</tr>
Expand All @@ -27,62 +27,53 @@
{{#if ticket.isDescriptionVisible}}
<small class="ui gray-text tiny">{{ticket.description}}</small>
{{/if}}
<div>
<small class="ui gray-text small">Sale ends on {{moment-format ticket.salesEndsAt 'ddd, DD MMMM YY, h:mm A'}}</small>
</div>
</td>
<td>{{moment-format ticket.salesEndsAt 'ddd, DD MMMM YY, h:mm A'}}</td>
{{#if ticket.discount}}
<td>
<div id="{{ticket.id}}_price" class="strike text">
{{this.eventCurrency}} {{format-money ticket.price}}
</div>
<div id="{{ticket.id}}_discount">
{{this.eventCurrency}} {{format-money (sub ticket.price ticket.discount)}}
{{#if this.taxInfo}}
{{#if this.showTaxIncludedMessage}}
<small class="ui gray-text small">
{{t 'includes'}} {{this.eventCurrency}} {{format-money ticket.includedTaxAmount}}
</small>
{{else}}
<small class="ui gray-text small">
+ {{this.eventCurrency}}
{{format-money (add (sub ticket.ticketPriceWithTax ticket.price) ticket.discount)}}
</small>
{{/if}}
<div>
<small class="ui gray-text tiny aligned right">({{this.taxInfo.name}})</small>
</div>
{{/if}}
</div>
</td>
{{else}}
<td id="{{ticket.id}}_price">
{{#if (eq ticket.type 'donation') }}
<div class="field">
<td></td>
<td id="{{ticket.id}}_price">
{{#if (eq ticket.type 'donation') }}
<div class="field m-0">
<div class="ui labeled input">
<label for="i_{{ticket.id}}_price" class="ui label">{{currency-symbol this.eventCurrency}}</label>
<Input
id="i_{{ticket.id}}_price"
@type="number"
@name={{ticket.id}} placeholder={{t "Enter Donation"}}
@min={{ticket.minPrice}}
@max={{ticket.maxPrice}}
@value={{ticket.price}} /><br>
@value={{ticket.price}}
@keyUp={{action "onChangeDonation"}} />
</div>
</div>
{{else}}
<div class="{{if ticket.discount 'strike text'}}">
{{currency-symbol this.eventCurrency}} {{format-money ticket.price}}
</div>
{{#if ticket.discount}}
<div>
{{currency-symbol this.eventCurrency}} {{format-money (sub ticket.price ticket.discount)}}
</div>
{{else}}
{{this.eventCurrency}} {{format-money ticket.price}}
{{/if}}
{{#if (and this.taxInfo (not-eq ticket.type 'free'))}}
{{#if this.showTaxIncludedMessage}}
{{/if}}
{{#if (and this.taxInfo (not-eq ticket.type 'free'))}}
<p>
{{#if this.taxInfo.isTaxIncludedInPrice}}
<small class="ui gray-text small">
{{t 'includes'}} {{this.eventCurrency}} {{format-money ticket.includedTaxAmount}}
{{t 'includes'}} {{currency-symbol this.eventCurrency}} {{format-money ticket.includedTaxAmount}}
</small>
{{else}}
<small class="ui gray-text small">
+ {{this.eventCurrency}} {{format-money (sub ticket.ticketPriceWithTax ticket.price)}}
+ {{currency-symbol this.eventCurrency}} {{format-money (sub ticket.ticketPriceWithTax ticket.price)}}
</small>
{{/if}}
<div>
<span>
<small class="ui gray-text tiny aligned right">({{this.taxInfo.name}})</small>
</div>
{{/if}}
</td>
{{/if}}
</span>
</p>
{{/if}}
</td>
<td>
<div class="field">
<UiDropdown
Expand All @@ -105,28 +96,35 @@
</div>
</td>
<td id='{{ticket.id}}_subtotal' class="ui right aligned">
{{#if this.taxInfo}}
{{this.eventCurrency}}
{{format-money (mult (sub ticket.ticketPriceWithTax ticket.discount) ticket.orderQuantity)}}
{{else}}
{{this.eventCurrency}} {{format-money (mult (sub ticket.price ticket.discount) ticket.orderQuantity)}}
{{/if}}
{{currency-symbol this.eventCurrency}} {{format-money ticket.subTotal}}
</td>
</tr>
{{/unless}}
{{/each}}
</tbody>
<tfoot class="full-width">
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th colspan="4">
<div class="ui right aligned small primary icon">
{{t 'Total'}}: {{this.eventCurrency}} {{format-money this.total}}
</div>
</th>
<td></td>
<td></td>
<td colspan="3">
<table class="ui small" style="float: right;">
<tbody>
{{#if orderAmount.tax}}
<tr><td>{{t 'Sub-Total'}}</td><td>{{currency-symbol this.eventCurrency}} {{format-money this.orderAmount.sub_total}}</td></tr>
<tr>
<td>
<div>{{t 'Tax'}} ({{this.orderAmount.tax.percent}}% {{this.orderAmount.tax.name}})</div>
{{#if orderAmount.tax.included}}
<small class="ui gray-text small">Included in Total</small>
{{/if}}
</td>
<td>{{currency-symbol this.eventCurrency}} {{this.orderAmount.tax.amount}}</td>
</tr>
{{/if}}
<tr><td>{{t 'Total'}}</td><td>{{currency-symbol this.eventCurrency}} {{format-money this.orderAmount.total}}</td></tr>
</tbody>
</table>
</td>
</tr>
</tfoot>
</table>
Expand Down
2 changes: 1 addition & 1 deletion app/utils/dictionary/payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export const paymentCurrencies: PaymentCurrency[] = [
{
paypal : true,
code : 'USD',
symbol : 'US$',
symbol : '$',
name : 'United States dollar',
stripe : true,
alipay : true,
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/helpers/currency-symbol-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module('Integration | Helper | currency-symbol', function(hooks) {

await render(hbs`{{currency-symbol inputValue}}`);

assert.equal(this.element.textContent.trim(), 'US$');
assert.equal(this.element.textContent.trim(), '$');
});
});

1 comment on commit eeb15a9

@vercel
Copy link

@vercel vercel bot commented on eeb15a9 Jun 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.