@zhiguang-gastrofy/capi
Version:
comany apis, including Northfork api and Gastrofy api
285 lines (243 loc) • 8.1 kB
text/typescript
import { HttpService } from './http.service';
import { parseImage, parsePrice, decimalPrice } from './utils';
import axios from 'axios';
const CancelToken = axios.CancelToken;
export class ResolveService {
private _NFHttp: any;
private _mainCancel: Function;
private _recipes:any;
total:any = {};
products = [];
ingredients = [];
resolving:boolean = false;
constructor( config?:any ) {
config = { ...config || {} };
this._NFHttp = new HttpService( { ...{
host: 'https://api.northfork.se/api',
}, ...config } );
}
cancel( type?:string ) {
if( ( !type || type ==='main' ) && this._mainCancel ) this._mainCancel();
if( !type || type ==='diff' ) {
}
}
/**
* the recipe id can be gastrofy_id or external_id:
* { gastrofy_id: 1, portions: 1 }
* OR
* { external_id: 1, portions: 1 }
*
* options: {
* tags: Array,
* storeProvider: String,
* storeIdentifier: String',
* productExceptions: Array,
* calculation: price | waste,
* prioritization: String,
* promotedBrand: String,
* params: {}
* }
*/
resolve( recipes:any, options:any ) {
this.resolving = true;
return this._NFHttp.post( 'smart-cart/recipes/resolve', {
recipes: recipes,
store: {
tags: options.tags || [],
provider: options.storeProvider,
identifier: options.storeIdentifier,
},
options: {
calculation: options.calculation,
prioritization:options.prioritization,
product_exceptions: options.productExceptions,
},
}, {
params: options.params,
promoted_brand: options.promotedBrand,
cancelToken: new CancelToken( ( c:any ) => {
this._mainCancel = c;
} ),
} ).then( ( res:any ) => {
this.resolving = false;
let data = res.data;
this.products = this._formatProducts( data.products );
this.ingredients = this._formaIngredients( data.recipes );
this._recipes = data.recipes;
this._calculateTotal();
return this;
}, ( err:any ) => {
this.resolving = false;
return err;
} );
}
// substitute can be new quantity or new product
substituteProduct( identifier:string, substitute:any ) {
let original = null;
for( let product of this.products ) {
if( product.substitute_identifier === identifier ) {
original = product;
break;
}
}
if( !original ) return;
// TODO: TO FIX:
// NOTE: The consumption of the replaced product is 0 from api, so set to 0 at frontend now
original.consumption = 0;
original.replaced = true;
if( typeof substitute === 'number' ) {
original.quantity = substitute;
} else {
for( let field in original ) {
if( field === 'substitute_identifier' || typeof substitute[field] === 'undefined' ) continue;
original[field] = substitute[field];
}
}
this._calculateTotal();
}
productsBySections() {
let sharedProducts = [];
let commonProducts = [];
let recipesProducts = [];
for( let product of this.products ) {
if( product.common ) commonProducts.push( product );
else if( product.shared ) sharedProducts.push( product );
else recipesProducts.push( product );
}
return {
common: commonProducts,
shared: sharedProducts,
recipes: this._recipes.map( ( recipe:any ) => {
let recipeProducts = [];
for( let ingredient of recipe.ingredients ) {
for( let product of recipesProducts ) {
for( let ingredientId of product.recipe_ingredient_ids ) {
if( ingredientId !== ingredient.id ) continue;
recipeProducts.push( product );
}
}
}
return {
id: recipe.id,
title: recipe.title,
portions: recipe.portions,
image_url: parseImage( recipe ),
products: recipeProducts,
};
} ),
};
}
productsByCategories() {
let index = {};
let result = [];
for( let product of this.products ) {
const category = product.categories[0] || { id: -1, sort_order: 999999999, title: null };
const categoryId = category.id;
let productIndex = index[ categoryId ];
if( productIndex === undefined ) {
productIndex = result.length;
index[categoryId] = productIndex;
result[productIndex] = {
id: category.id,
title: category.title,
sort_order: category.sort_order,
products: [],
};
}
result[productIndex].products.push( product );
}
result.sort( ( a:any, b:any ) => {
if( a.sort_order > b.sort_order ) return 1;
return -1;
} );
return result;
}
private _formatProducts( data ) {
let products = [];
for( let productGroup of data ) {
products = products.concat( productGroup.map( ( product:any ) => {
product.brand = product.brand && product.brand !== 'na'? product.brand: null;
product.price = parsePrice( product.price );
product.is_active = product.price>0&&(product.strategy!=='out_of_stock'&&product.strategy!=='replaced_out_of_stock');
product.replaced = product.strategy === 'replaced' || product.strategy === 'replaced_out_of_stock';
product.recipe_ingredient_ids = product.recipe_ingredient_ids.map( item => item.id );
product.common = product.common === true;
product.shared = product.recipe_ingredient_ids.length > 1;
product.name = product.name.trim();
delete product.strategy;
delete product.partner_attributes;
delete product.ean;
delete product.sub_text;
product.ingredients = ( ( ids:any ) => {
return () => {
return ids.map( ( id:any ) => {
for( let ingredient of this.ingredients ) {
if( ingredient.id === id ) return ingredient;
}
} );
};
} )( product.recipe_ingredient_ids );
return product;
} ) );
}
return products;
}
private _formaIngredients( recipes:any ) {
let ingredients = [];
for( let recipe of recipes ) {
ingredients = ingredients.concat( recipe.ingredients.map( ( ingredient:any ) => {
ingredient.amount = ingredient.amount.replace( /(\.\w)0$/, ( v:any, m:any ) => {
return m > 0 ? m: '';
} );
ingredient.products = ( ( ingredientId:number ) => {
return () => {
let result = [];
for( let product of this.products ) {
for( let id of product.recipe_ingredient_ids ) {
if( id === ingredientId ) {
result.push( product );
break;
}
}
}
return result;
};
} )( ingredient.id );
return ingredient;
} ) );
}
return ingredients;
}
private _calculateTotal() {
let total = {
price: 0,
price_with_common: 0,
consumption_price: 0,
consumption_price_with_common: 0,
quantity: 0,
quantity_with_common: 0,
checkout_price: 0,
checkout_quantity: 0,
};
for( let product of this.products ) {
const curTotal = product.price * product.quantity;
const consumptionPrice = curTotal * product.consumption;
total.price_with_common += curTotal;
total.consumption_price_with_common += consumptionPrice;
total.quantity_with_common += product.quantity;
if( !product.common || product.replaced ) {
total.price += curTotal;
total.consumption_price += consumptionPrice;
total.quantity += product.quantity;
product.quantity = product.quantity;
if( product.is_active ) {
total.checkout_price += curTotal;
total.checkout_quantity += product.quantity;
}
}
}
for( let totalField in total ) {
this.total[totalField] = decimalPrice( total[ totalField ] );
}
}
}