Skip to content
This repository has been archived by the owner on May 21, 2020. It is now read-only.

feat: implemented user order details #360

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions packages/commercetools/api-client/src/fragments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export const CartFragment = `

export const OrderFragment = `
${LineItemFragment}
${AddressFragment}

fragment DefaultOrder on Order {
lineItems {
Expand All @@ -141,7 +142,29 @@ export const OrderFragment = `
totalPrice {
centAmount
}
billingAddress {
...DefaultAddress
}
shippingAddress {
...DefaultAddress
}
orderNumber
orderState
taxedPrice {
totalNet {
centAmount
}
totalGross {
centAmount
}
taxPortions {
rate
amount {
centAmount
}
name
}
}
id
version
createdAt
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,63 @@
import {
getOrderDate,
getOrderId,
getOrderNumber,
getOrderStatus,
getOrderPrice
getOrderPrice,
getOrderItems,
getOrderNetValue,
getOrderGrossValue,
getOrderTaxValue,
getOrderTaxRate,
getOrderBillingAddress,
getOrderShippingAddress,
getOrderBillingAddressValues,
getOrderShippingAddressValues
} from './../../src/getters/orderGetters';
import { OrderState, Order } from './../../src/types/GraphQL';

const order: Order = {
const generatePrice = (centAmount: number) => ({
centAmount,
currencyCode: 'USD'
});

const order: Order = Object.freeze({
createdAt: 123456789,
id: '645ygdf',
orderNumber: 'abcdef',
orderState: OrderState.Complete,
totalPrice: {
centAmount: 12345,
currencyCode: 'USD'
}
} as any;
totalPrice: generatePrice(12345),
taxedPrice: {
totalNet: generatePrice(1111),
totalGross: generatePrice(2222),
taxPortions: [
{
amount: generatePrice(3333),
rate: 0.15
}
]
},
billingAddress: {
id: '1234',
firstName: 'Vue',
lastName: 'Developer',
__typename: 'Address'
},
shippingAddress: {
id: '5678',
firstName: 'Java',
lastName: 'Script',
__typename: 'Address'
},
lineItems: [
{
id: 'product-1'
},
{
id: 'product-2'
}
]
}) as any;

describe('[commercetools-getters] order getters', () => {
it('returns default values', () => {
Expand All @@ -28,15 +71,95 @@ describe('[commercetools-getters] order getters', () => {
expect(getOrderDate(order)).toEqual(123456789);
});

it('returns order number', () => {
it('returns order id', () => {
expect(getOrderId(order)).toEqual('645ygdf');
});

it('returns order number', () => {
const orderWithoutNumber = {
id: 'just-id'
} as Order;

expect(getOrderNumber(order)).toEqual('abcdef');
expect(getOrderNumber(orderWithoutNumber)).toEqual('just-id');
});

it('returns status', () => {
expect(getOrderStatus(order)).toEqual(OrderState.Complete);
});

it('returns total gross', () => {
expect(getOrderPrice(order)).toEqual(123.45);
});

it('returns net value', () => {
expect(getOrderNetValue(order)).toEqual(11.11);
});

it('returns gross value', () => {
expect(getOrderGrossValue(order)).toEqual(22.22);
});

it('returns tax value', () => {
expect(getOrderTaxValue(order)).toEqual(33.33);
});

it('returns tax rate', () => {
expect(getOrderTaxRate(order)).toEqual(15);
});

it('returns billing address', () => {
const orderWithoutAddress = {} as Order;
const address = getOrderBillingAddress(order);

expect(Object.keys(address)).toHaveLength(4);
expect(address.id).toEqual('1234');
expect(address.firstName).toEqual('Vue');
expect(address.lastName).toEqual('Developer');
expect(address.__typename).toEqual('Address');
expect(getOrderBillingAddress(orderWithoutAddress)).toBeNull();
});

it('returns shipping address', () => {
const orderWithoutAddress = {} as Order;
const address = getOrderShippingAddress(order);

expect(Object.keys(address)).toHaveLength(4);
expect(address.id).toEqual('5678');
expect(address.firstName).toEqual('Java');
expect(address.lastName).toEqual('Script');
expect(address.__typename).toEqual('Address');
expect(getOrderShippingAddress(orderWithoutAddress)).toBeNull();
});

it('returns transformed billing address values', () => {
const values = getOrderBillingAddressValues(order);

expect(Array.isArray(values)).toBeTruthy();
expect(values).toHaveLength(2);
expect(values[0].property).toEqual('First Name');
expect(values[1].property).toEqual('Last Name');
expect(values[0].value).toEqual('Vue');
expect(values[1].value).toEqual('Developer');
});

it('returns transformed shipping address values', () => {
const values = getOrderShippingAddressValues(order);

expect(Array.isArray(values)).toBeTruthy();
expect(values).toHaveLength(2);
expect(values[0].property).toEqual('First Name');
expect(values[1].property).toEqual('Last Name');
expect(values[0].value).toEqual('Java');
expect(values[1].value).toEqual('Script');
});

it('returns line items', () => {
const items = getOrderItems(order);

expect(Array.isArray(items)).toBeTruthy();
expect(items).toHaveLength(2);
expect(items[0].id).toEqual('product-1');
expect(items[1].id).toEqual('product-2');
});
});
49 changes: 46 additions & 3 deletions packages/commercetools/composables/src/getters/orderGetters.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,69 @@
import { UserOrderGetters, AgnosticOrderStatus } from '@vue-storefront/interfaces';
import { Order, OrderState } from './../types/GraphQL';
import { Order, OrderState, LineItem, Money, Address } from './../types/GraphQL';

export const getOrderDate = (order: Order): string => order?.createdAt || '';

export const getOrderId = (order: Order): string => order?.id || '';

export const getOrderNumber = (order: Order): string => order?.orderNumber || getOrderId(order);
Qrzy marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

how that is different from ID? Did you made sure that this field is not specific to commercetools?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A lot of ecommerce platforms have the ID and Order Number separately.

Copy link
Collaborator

Choose a reason for hiding this comment

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

export const getOrderId = (order: Order): string => order?.id || order?.orderNumber;

Copy link
Contributor

@filrak filrak Apr 10, 2020

Choose a reason for hiding this comment

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

does a lot mean all of them? keep in mind that helpers are for the UI, are both needed in the UI? Imho @andrzejewsky proposed right solution


const orderStatusMap = {
[OrderState.Open]: AgnosticOrderStatus.Open,
[OrderState.Confirmed]: AgnosticOrderStatus.Confirmed,
[OrderState.Complete]: AgnosticOrderStatus.Complete,
[OrderState.Cancelled]: AgnosticOrderStatus.Cancelled
};

const getPrice = (money: Money): number | null => money && money.centAmount ? money.centAmount / 100 : null;
defudef marked this conversation as resolved.
Show resolved Hide resolved

export const getOrderStatus = (order: Order): AgnosticOrderStatus | '' => order?.orderState ? orderStatusMap[order.orderState] : '';

export const getOrderPrice = (order: Order): number | null => order ? order.totalPrice.centAmount / 100 : null;
export const getOrderItems = (order: Order): LineItem[] => order?.lineItems || [];

export const getOrderPrice = (order: Order): number | null => getPrice(order?.totalPrice);

export const getOrderNetValue = (order: Order): number | null => getPrice(order?.taxedPrice?.totalNet);

export const getOrderGrossValue = (order: Order): number | null => getPrice(order?.taxedPrice?.totalGross);

export const getOrderTaxValue = (order: Order): number | null => getPrice(order?.taxedPrice?.taxPortions[0]?.amount);

export const getOrderTaxRate = (order: Order): number => (order?.taxedPrice?.taxPortions[0]?.rate || 0) * 100;
defudef marked this conversation as resolved.
Show resolved Hide resolved

export const getOrderBillingAddress = (order: Order): Address | null => order?.billingAddress || null;

export const getOrderShippingAddress = (order: Order): Address | null => order?.shippingAddress || null;

type KeyValueAddress = { property: string; value: string }[];

const transformAddressToArray = (address: Address | object): KeyValueAddress => Object.entries(address)
.filter(([property, value]) => value !== null && !['id', '__typename'].includes(property))
.map(([property, value]) => ({
property: (property || '')
.replace(/([A-Z])/g, ' $1')
.replace(/^./, (str) => str.toUpperCase()),
value
}));

export const getOrderBillingAddressValues = (order: Order): KeyValueAddress => transformAddressToArray(getOrderBillingAddress(order) || {});

export const getOrderShippingAddressValues = (order: Order): KeyValueAddress => transformAddressToArray(getOrderShippingAddress(order) || {});

const orderGetters: UserOrderGetters<Order> = {
getDate: getOrderDate,
getId: getOrderId,
getNumber: getOrderNumber,
getStatus: getOrderStatus,
getPrice: getOrderPrice
getPrice: getOrderPrice,
getItems: getOrderItems,
getNetValue: getOrderNetValue,
getGrossValue: getOrderGrossValue,
getTaxValue: getOrderTaxValue,
getTaxRate: getOrderTaxRate,
getBillingAddress: getOrderBillingAddress,
getShippingAddress: getOrderShippingAddress,
getBillingAddressValues: getOrderBillingAddressValues,
getShippingAddressValues: getOrderShippingAddressValues
};

export default orderGetters;
2 changes: 1 addition & 1 deletion packages/core/theme-module/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ module.exports = function DefaultThemeModule(moduleOptions) {
});
routes.push({
name: 'my-account',
path: '/my-account/:pageName?',
path: '/my-account/:pageName?/:id?',
component: resolve(projectLocalThemeDir, 'pages/MyAccount.vue')
});
routes.push({
Expand Down
54 changes: 33 additions & 21 deletions packages/core/theme-module/theme/pages/MyAccount.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,24 @@
<SfContentPage title="My reviews">
<MyReviews />
</SfContentPage>
<SfContentPage title="Order details">
<OrderDetails v-if="entityId" :orderId="entityId" />
defudef marked this conversation as resolved.
Show resolved Hide resolved
defudef marked this conversation as resolved.
Show resolved Hide resolved
<p v-else>Not found</p>
</SfContentPage>
</SfContentCategory>
<SfContentPage title="Log out" />
</SfContentPages>
</div>
</template>
<script>
import { SfBreadcrumbs, SfContentPages } from '@storefront-ui/vue';
import { ref } from '@vue/composition-api';
import MyProfile from './MyAccount/MyProfile';
import ShippingDetails from './MyAccount/ShippingDetails';
import LoyaltyCard from './MyAccount/LoyaltyCard';
import MyNewsletter from './MyAccount/MyNewsletter';
import OrderHistory from './MyAccount/OrderHistory';
import OrderDetails from './MyAccount/OrderDetails';
import MyReviews from './MyAccount/MyReviews';
import auth from '../middleware/auth';

Expand All @@ -63,10 +69,36 @@ export default {
LoyaltyCard,
MyNewsletter,
OrderHistory,
OrderDetails,
MyReviews
},
data() {
setup(props, context) {
const { $route, $router } = context.root;
const activePage = ref('My profile');
const entityId = ref(null);

const changeActivePage = (title) => {
if (title === 'Log out') {
return;
}

$router.push(`/my-account/${title.toLowerCase().replace(' ', '-')}`);
};

const { pageName, id } = $route.params;

if (pageName) {
activePage.value = (pageName.charAt(0).toUpperCase() + pageName.slice(1)).replace('-', ' ');
}

if (id) {
entityId.value = id;
}

return {
changeActivePage,
activePage,
entityId,
breadcrumbs: [
{
text: 'Home',
Expand Down Expand Up @@ -118,26 +150,6 @@ export default {
]
}
};
},
computed: {
activePage() {
const { pageName } = this.$route.params;

if (pageName) {
return (pageName.charAt(0).toUpperCase() + pageName.slice(1)).replace('-', ' ');
}

return 'My profile';
}
},
methods: {
changeActivePage(title) {
if (title === 'Log out') {
return;
}

this.$router.push(`/my-account/${title.toLowerCase().replace(' ', '-')}`);
}
}
};
</script>
Expand Down
Loading