From 2b4c515b3efc1be17dc807075a5d4b6857c46e95 Mon Sep 17 00:00:00 2001 From: olivier evalet Date: Sat, 12 Nov 2016 11:07:06 +0100 Subject: [PATCH] oe- discount based on amount (#82) * Non admin can create more than one shop (#73) * #71 non admin user can create more than one shop * #71 non admin user can create more than one shop * #71 non admin user can create more than one shop * enhance auth functions * #71 non admin user can create more than one shop * #69 validate fields for discount * #72 starting with precaching * #71 fix issue with shop validation * initial implementation for discount * #69 implement the order process that include discounts * #69 better validation for discount value * fix typo error * make our participation lower * make our participation lower for stripe * #69 fix issue on fees calculation * #69 fix issue on fees calculation * accept more photos on this shops * upgrade node vm * accept image gallery * #69 better bill layout * #69 validate report with real e2e data from production * support mongodb 3.2 on travis * use a npm dep badge * debug travis issue * fix issue for duplicate creation * resolve travis issue * use mongo 3.0 * #69 remove useless log * sort should work on disk when high memory usage * open 1218 * fix allowDiskUse criteria on aggregate * #69 fix issue with orders counting * #69 orders counting was not good * #69 orders counting was not good * missing issue label * #80 remove ability for user to modify his shops and payments from update method * #80 remove ability for user to modify his shops and payments from update method * #69 lot of fixes after e2e testing. Big one, was the payment fees was not stored in db * on delete payment error we trace the payment data * #69 fix issue with product selection for the next shipping * #69 select product is not working well * #69 small fixes * #69 small fixes * #69 first step to test email after new order --- .travis.yml | 15 +- README.md | 4 +- config/config-shared.js | 15 +- controllers/orders.js | 265 +- controllers/users.js | 25 +- controllers/validate/validate.js | 11 +- emails/order-billing/html.ejs | 8 +- emails/order-new/html.ejs | 11 +- maintain/0032.orders_fees_charge.js | 17 + models/categories.js | 10 +- models/config.js | 4 +- models/lib/order.core.js | 17 +- models/lib/order.stats.js | 333 +- models/lib/order.utils.js | 82 +- models/order.js | 30 +- models/products.js | 30 +- models/shops.js | 2 + models/users.js | 8 +- ...orders.repport.js => api.orders.report.js} | 2 +- test/api.users.js | 2 + test/category.js | 2 +- test/fixtures/Orders.find.js | 40 + test/fixtures/Orders.payment.capture.js | 41 +- test/fixtures/Orders.payment.js | 21 +- test/fixtures/Orders.price.js | 17 +- test/fixtures/Orders.price.merchant.js | 17 +- test/fixtures/Orders.report.022016.js | 4071 +++++++++++++++++ test/fixtures/Orders.report.discount.js | 751 +++ .../{Orders.repport.js => Orders.report.js} | 0 test/order.create.success.js | 10 + test/order.create.success.withdiscount.js | 298 ++ test/order.find.product.js | 2 +- test/order.report.includeDiscount.js | 116 + test/order.validate.price.js | 12 +- test/order.validate.report.022016.js | 119 + test/order.validate.report.js | 241 + test/order.validate.repport.js | 194 - 37 files changed, 6358 insertions(+), 485 deletions(-) create mode 100644 maintain/0032.orders_fees_charge.js rename test/{api.orders.repport.js => api.orders.report.js} (98%) create mode 100644 test/fixtures/Orders.report.022016.js create mode 100644 test/fixtures/Orders.report.discount.js rename test/fixtures/{Orders.repport.js => Orders.report.js} (100%) create mode 100644 test/order.create.success.withdiscount.js create mode 100644 test/order.report.includeDiscount.js create mode 100644 test/order.validate.report.022016.js create mode 100644 test/order.validate.report.js delete mode 100644 test/order.validate.repport.js diff --git a/.travis.yml b/.travis.yml index cc93c4b..9ff54fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,21 @@ language: node_js node_js: - - "0.10" + - "4.2.6" + services: - mongodb + +sudo: false + +addons: + apt: + sources: + - mongodb-upstart + - mongodb-3.0-precise + packages: + - mongodb-org-server + - mongodb-org-shell + env: - NODE_ENV="test" diff --git a/README.md b/README.md index 5a5fd17..16293cb 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Karibou-api -Karibou is an open-source project aim to help the creation of an +Karibou.ch is an open-source project aim to help the creation of an online community marketplace. Our goal is to allow local food producers, artisans and artists to sell their products locally. There is alpha frontend available here http://karibou.evaletolab.ch/ -[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/evaletolab/karibou-api/trend.png)](https://bitdeli.com/free "Bitdeli Badge") +![NPM](https://david-dm.org/evaletolab/karibou-api.svg) [![Build Status](https://travis-ci.org/evaletolab/karibou-api.svg?branch=master)](https://travis-ci.org/evaletolab/karibou-api) ## Getting started diff --git a/config/config-shared.js b/config/config-shared.js index 1045333..f1803c0 100644 --- a/config/config-shared.js +++ b/config/config-shared.js @@ -30,9 +30,9 @@ module.exports = { hypercenter:11.9, periphery:14.90 }, // shipping price - priceA:2, - priceB:3, - periphery:["1212","1213","1219","1223","1224","1225","1226","1228","1231","1232","1233","1234","1253","1255","1256","1257","1258"] + priceA:0, + priceB:0, + periphery:["1212","1213","1218","1219","1223","1224","1225","1226","1228","1231","1232","1233","1234","1253","1255","1256","1257","1258"] }, issue:{ @@ -43,6 +43,7 @@ module.exports = { "issue_missing_validation", "issue_missing_customer_support", "issue_wrong_packing", + "issue_wrong_product", "issue_wrong_client_id", "issue_wrong_product_quality", "issue_late_delivry" @@ -64,7 +65,7 @@ module.exports = { location:{ list:[ "1201","1202","1203","1204","1205","1206","1207","1208","1209","1227", - "1212","1213","1219","1223","1224","1225","1226","1228","1231","1232","1233","1234","1253","1255","1256","1257","1258"] + "1212","1213","1218","1219","1223","1224","1225","1226","1228","1231","1232","1233","1234","1253","1255","1256","1257","1258"] }, region:{ list:["Genève", "Carouge,GE"] @@ -125,9 +126,9 @@ module.exports = { cancelreason:["customer", "fraud", "inventory", "system","timeout","other"], status:["failure","created","reserved","partial","fulfilled"], gateway:[ - {label:"postfinance card",fees:0.00}, - {label:"american express",fees:0.00}, - {label:"visa",fees:0.000}, + {label:"postfinance card",fees:0.0}, + {label:"american express",fees:0.01}, + {label:"visa",fees:0.00}, {label:"mastercard",fees:0.0}, {label:"wallet", fees:0.000}, {label:"invoice",fees:0.000}, diff --git a/controllers/orders.js b/controllers/orders.js index 9680220..2bbf6cf 100644 --- a/controllers/orders.js +++ b/controllers/orders.js @@ -365,37 +365,47 @@ exports.create=function(req,res){ } var oid=order.oid; + // + // authorize payment payment.for(order.payment.issuer).authorize(order) .then(function(order){ - // - // prepare and send mail - var subTotal=order.getSubTotal(),shippingFees=order.getShippingPrice(); - var mail={ - order:order, - created:order.getDateString(order.created), - shippingFees:shippingFees, - paymentFees:payment.fees(order.payment.issuer,subTotal+shippingFees).toFixed(2), - totalWithFees:order.getTotalPrice().toFixed(2), - shippingWhen:order.getDateString(), - subTotal:subTotal.toFixed(2), - origin:req.header('Origin')||config.mail.origin, - withHtml:true - }; - bus.emit('sendmail', - order.email, - 'Confirmation de votre commande Karibou '+order.oid, - mail, - 'order-new', - function(err,status){ - //TODO log activities - if(err)console.log('---------------------------create',order.oid,err) - }) - return res.json(order) - }) - .fail(function(err){ - bus.emit('system.message',"[order-create] :",{error:err.message,order:order.oid,customer:order.email}); - return res.json(400,err.message||err) - }) + // + // prepare and send mail + var subTotal=order.getSubTotal(), + totalDiscount=order.getTotalDiscount(), + extraDiscount=order.getExtraDiscount(), + shippingFees=order.getShippingPrice(), + paymentFees=(order.payment.fees.charge*(subTotal+shippingFees-totalDiscount)).toFixed(2); + var mail={ + order:order, + created:order.getDateString(order.created), + shippingFees:Math.max(shippingFees-Math.max(totalDiscount-paymentFees,0),0).toFixed(2), + paymentFees:(Math.max(paymentFees-totalDiscount,0)).toFixed(2), + totalWithFees:order.getTotalPrice().toFixed(2), + totalDiscount: totalDiscount.toFixed(2), + extraDiscount: extraDiscount, + shippingWhen:order.getDateString(), + subTotal:subTotal.toFixed(2), + origin:req.header('Origin')||config.mail.origin, + withHtml:true + }; + bus.emit('sendmail', + order.email, + 'Confirmation de votre commande Karibou '+order.oid, + mail, + 'order-new', + function(err,status){ + //TODO log activities + if(err)console.log('---------------------------create',order.oid,err) + }) + order=order.toObject(); + order.mail=mail; + return res.json(order) + }) + .fail(function(err){ + bus.emit('system.message',"[order-create] :",{error:err.message,order:order.oid,customer:order.email}); + return res.json(400,err.message||err) + }) }); }; @@ -546,6 +556,7 @@ exports.refund=function(req,res){ created:order.getDateString(order.created), origin:req.header('Origin')||config.mail.origin, totalWithFees:order.getTotalPrice().toFixed(2), + discount: order.getTotalDiscount().toFixed(2), withHtml:true }; bus.emit('sendmail', @@ -582,43 +593,49 @@ exports.capture=function(req,res){ return res.json(400, "La commande "+req.params.oid+" n'existe pas."); } + // + // capture payment payment.for(order.payment.issuer).capture(order, req.body.reason) .then(function(order){ - // - // prepare and send mail - var subTotal=order.getSubTotal(),shippingFees=order.getShippingPrice(); - var mail={ - order:order, - created:order.getDateString(order.created), - shippingFees:shippingFees, - paymentFees:payment.fees(order.payment.issuer,subTotal+shippingFees).toFixed(2), - totalWithFees:order.getTotalPrice().toFixed(2), - shippingWhen:order.getDateString(), - subTotal:subTotal.toFixed(2), - origin:req.header('Origin')||config.mail.origin, - withHtml:true - }; - bus.emit('sendmail', - order.email, - 'Facture de votre commande Karibou '+order.oid, - mail, - 'order-billing', - function(err,status){ - //TODO log activities - if(err)console.log('---------------------------capture',order.oid,err) - }) - - - return res.json(_.extend({mail:mail},order.toObject())) - }) - .fail(function(err){ - bus.emit('system.message',"[order-capture] :",{error:err.message,order:order.oid,customer:order.email}); - return res.status(400).send(err.message) - }) - - - }) + // + // prepare and send mail + var subTotal=order.getSubTotal(), + totalDiscount=order.getTotalDiscount(), + extraDiscount=order.getExtraDiscount(), + shippingFees=order.getShippingPrice(), + paymentFees=(order.payment.fees.charge*(subTotal+shippingFees-totalDiscount)).toFixed(2); + var mail={ + order:order, + created:order.getDateString(order.created), + shippingFees:Math.max(shippingFees-Math.max(totalDiscount-paymentFees,0),0).toFixed(2), + paymentFees:(Math.max(paymentFees-totalDiscount,0)).toFixed(2), + totalWithFees:order.getTotalPrice().toFixed(2), + totalDiscount: totalDiscount.toFixed(2), + extraDiscount:extraDiscount, + shippingWhen:order.getDateString(), + subTotal:subTotal.toFixed(2), + origin:req.header('Origin')||config.mail.origin, + withHtml:true + }; + bus.emit('sendmail', + order.email, + 'Facture de votre commande Karibou '+order.oid, + mail, + 'order-billing', + function(err,status){ + //TODO log activities + if(err)console.log('---------------------------capture',order.oid,err) + }) + + + return res.json(_.extend({mail:mail},order.toObject())) + }) + .fail(function(err){ + bus.emit('system.message',"[order-capture] :",{error:err.message,order:order.oid,customer:order.email}); + return res.status(400).send(err.message) + }); + }); } @@ -783,28 +800,10 @@ exports.invoicesByUsers=function(req,res){ return res.status(400).send( err.message); } + /** var criteria={}, result=[]; - // get the date - criteria.from=new Date(); - if(req.params.year){ - criteria.from.setYear(parseInt(req.params.year)) - } - - // select a shipping month - criteria.from.setDate(1) - criteria.from.setMonth(parseInt(req.params.month)-1) - criteria.from.setHours(1,0,0,0) - criteria.to=new Date(criteria.from); - criteria.to.setDate(criteria.from.daysInMonth()) - criteria.to.setHours(23,0,0,0) - criteria.fulfillment='fulfilled' - - Orders.findByCriteria(criteria, function(err,orders){ - if(err){ - return res.status(400).send(errorHelper(err.message||err)); - } // sort by date and customer function byDateAndUser(o1,o2){ @@ -822,106 +821,35 @@ exports.invoicesByUsers=function(req,res){ // // oid, date, customer, amount, fees, fees, total - result.push(['oid','shipping','customer','amount','sfees','pfees','status','total']) - orders.sort(byDateAndUser).forEach(function(order){ - var subTotal=order.getSubTotal(); - var shippingFees=order.getShippingPrice(); - result.push({ - oid:order.oid, - shipping:Orders.formatDate(order.shipping.when), - customer:order.email, - amount:subTotal.toFixed(2), - shippingFees:shippingFees, - paymentFees:payment.fees(order.payment.issuer,subTotal+shippingFees).toFixed(2), - payment:order.payment.status, - total:order.getTotalPrice().toFixed(2) - }) - total+=parseFloat(order.getTotalPrice().toFixed(2)); - amount+=parseFloat(order.getSubTotal().toFixed(2)); - shipping+=shippingFees; - }) - result.push(['','','',amount,shipping,'','',total]) + result.push(['oid','shipping','customer','amount','sfees','pfees','status','total']); res.setHeader('Content-disposition', 'attachment; filename=invoices-users-'+criteria.from.getMonth()+''+criteria.from.getYear()+'.csv'); - res.csv(result) - - }); + res.csv(result); + **/ } // -// get repport by shop +// get report by shop exports.invoicesByShops=function(req,res){ try{ - if(!req.params.month)throw new Error('Le mois est obligatoire'); + if(req.params.month){} if(req.params.year){} }catch(err){ return res.status(400).send( err.message); } - var criteria={}, result=[], showAll=req.query.all||false, output=req.query.output||'json'; - - - criteria.closed=true; - criteria.fulfillment='fulfilled'; - - parseCriteria(criteria,req) - - // get the date - if(criteria.from &&!criteria.to){ - criteria.to=new Date(criteria.from); - criteria.to.setDate(criteria.from.daysInMonth()); - criteria.to.setHours(23,0,0,0); - } - - // - // do not hide !fulfilled items - if(req.query.all){ - criteria.showAll=true; - } // - // restrict to a shop name - // 0) no shops given => you should be admin - // 1) a list of shops is given => you should be admin - // 2) user shops => is the default - if(req.user.isAdmin()){ - // admin can specify the shops - if(req.query.shops){ - criteria.shop=req.query.shops - } + // grouped + var criteria={grouped:true}, result=[]; - }else{ - // not admin and having almost one shop - criteria.shop=req.user.shops.map(function(i){ return i.urlpath}) + if(req.params.month){ + criteria.month=parseInt(req.params.month); } - - Orders.generateRepportForShop(criteria,function(err,repport){ - if(err){ - return res.status(400).send(errorHelper(err.message||err)); - } - res.json(repport) - }); - -} - -// -// get repport by shop -exports.invoicesByShops2=function(req,res){ - try{ - if(!req.params.month)throw new Error('Le mois est obligatoire'); - if(req.params.year){} - }catch(err){ - return res.status(400).send( err.message); + if(req.params.year){ + criteria.year=parseInt(req.params.year); } - var criteria={}, result=[], showAll=req.query.all||false, today=new Date(),output=req.query.output||'json'; - - - criteria.month=req.params.month; - criteria.year=req.params.year||today.getFullYear(); - - - // // restrict to a shop name @@ -931,7 +859,7 @@ exports.invoicesByShops2=function(req,res){ if(req.user.isAdmin()){ // admin can specify the shops if(req.query.shops){ - criteria.shop=req.query.shops + criteria.shop=req.query.shops; } }else{ @@ -939,11 +867,14 @@ exports.invoicesByShops2=function(req,res){ criteria.shop=req.user.shops.map(function(i){ return i.urlpath}) } - Orders.getCAByYearMonthAndVendor(criteria,function(err,repport){ + + Orders.getCAByVendor(criteria,function(err,report){ if(err){ return res.status(400).send(errorHelper(err.message||err)); } - res.json(repport[criteria.year][criteria.month]) + // + // export in CSV! http://www.mircozeiss.com/json2csv/ + res.json(report) }); } diff --git a/controllers/users.js b/controllers/users.js index 445993c..b2a011b 100644 --- a/controllers/users.js +++ b/controllers/users.js @@ -205,26 +205,11 @@ exports.update=function(req,res){ delete req.body.email['status']; } - // - // admin can update the status here - if(req.body.status!==undefined){ - delete req.body['status']; - } - - // - // some admin updates - if(req.body.roles){ - delete req.body['roles']; - } - if(req.body.rank!==undefined){ - delete req.body['rank']; - } - if(req.body.gateway_id!==undefined){ - delete req.body['gateway_id']; - } - if(req.body.merchant!==undefined){ - delete req.body['merchant']; - } + delete req.body['status']; + delete req.body['rank']; + delete req.body['roles']; + delete req.body['gateway_id']; + delete req.body['merchant']; } diff --git a/controllers/validate/validate.js b/controllers/validate/validate.js index 4ff8bed..ac10245 100644 --- a/controllers/validate/validate.js +++ b/controllers/validate/validate.js @@ -323,10 +323,15 @@ exports.shop=function(shop){ if(shop.discount){ ifCheck(shop.discount.active,"Erreur system p10").isBoolean(); - ifCheck(shop.discount.threshold,"Le format du seuil n'est pas correct").isFloat(); - ifCheck(shop.discount.amount,"Le format du montant n'est pas correct").isFloat(); + ifCheck(shop.discount.threshold,"Le format du seuil à commandé n'est pas correct").isFloat(); + ifCheck(shop.discount.amount,"Le format du participation financière n'est pas correct").isFloat(); if(shop.discount.active&&(!shop.discount.threshold||!shop.discount.amount)){ - throw new Error("Vous avez activé la prise en charge client sans remplir le formulaire"); + throw new Error("Vous avez activé la prise en charge de la livraison sans remplir le formulaire"); + } + if(shop.discount.amount&&shop.discount.threshold){ + if(shop.discount.amount>=shop.discount.threshold){ + throw new Error("Votre participation financière ne peut pas être plus élevé que le montant acheté"); + } } } diff --git a/emails/order-billing/html.ejs b/emails/order-billing/html.ejs index c086562..08c1b90 100644 --- a/emails/order-billing/html.ejs +++ b/emails/order-billing/html.ejs @@ -11,9 +11,11 @@ Veuillez trouver votre facture Karibou pour votre commande <%= order.oid %> du < * ------------------ * Sous total <%= subTotal %> CHF * Frais de livraison <%= shippingFees %> CHF -* Frais de paiement <%= paymentFees %> CHF +* Frais de paiement <%= paymentFees %> CHF<%if (extraDiscount>0) {%> +* Bonus commerçants -<%= extraDiscount %> CHF<% } %> * ------------------ -* Montant total <%= totalWithFees %> CHF +* Montant total <%= totalWithFees %> CHF<%if (totalDiscount>0) {%> +* Rabais commerçants <%= totalDiscount %> CHF<% } %> * <%if (order.payment.issuer==='invoice') {%> @@ -35,7 +37,7 @@ Avec nos meilleurs messages,
| ' / __ _ _ __ _| |__ ___ _ _ | < / _` | '__| | '_ \ / _ \| | | | | . \ (_| | | | | |_) | (_) | |_| | - |_|\_\__,_|_| |_|_.__/ \___/ \__,_| + |_|\_\__,_|_| |_|_.__/ \___/ \__,_|.ch ----
diff --git a/emails/order-new/html.ejs b/emails/order-new/html.ejs index 791443b..5e41ec7 100644 --- a/emails/order-new/html.ejs +++ b/emails/order-new/html.ejs @@ -69,14 +69,17 @@ Vous trouverez ci-dessous le détail de votre commande
* ------------------ * Sous total <%= subTotal %> CHF * Frais de livraison <%= shippingFees %> CHF -* Frais de paiement <%= paymentFees %> CHF +* Frais de paiement <%= paymentFees %> CHF<%if (extraDiscount>0) {%> +* Bonus commerçants -<%= extraDiscount %> CHF<% } %> * ------------------ -* Montant total provisoire <%= totalWithFees %> CHF +* Montant total provisoire <%= totalWithFees %> CHF<%if (totalDiscount>0) {%> +* Rabais commerçants <%= totalDiscount %> CHF<% } %> *

Récapitulatif

Numéro de commande: <%= order.oid %>
Méthode de paiement: <%= order.payment.issuer %>
+Rabais commerçants: <%= totalDiscount %>
Montant total provisoire: <%= totalWithFees %> CHF
Date de livraison: Le <%= shippingWhen %>
Adresse de livraison:
@@ -85,7 +88,7 @@ Adresse de livraison:
# <%- order.shipping.postalCode %>, <%- order.shipping.region %>

Paiement et montant

-Vous recevrez une facture détaillée par e-mail avant la livraison.
+Vous recevrez une facture détaillée par e-mail au moment de la livraison.
Le total de la commande peut être ajusté dans le cas où vous avez commandé des produits à poids variables dont le prix est connu le jour de la livraison. Aussi, si un produit devait être en rupture de stock, il sera déduit de la facture finale.

@@ -96,7 +99,7 @@ Avec nos meilleurs messages,
| ' / __ _ _ __ _| |__ ___ _ _ | < / _` | '__| | '_ \ / _ \| | | | | . \ (_| | | | | |_) | (_) | |_| | - |_|\_\__,_|_| |_|_.__/ \___/ \__,_| + |_|\_\__,_|_| |_|_.__/ \___/ \__,_|.ch ----
diff --git a/maintain/0032.orders_fees_charge.js b/maintain/0032.orders_fees_charge.js new file mode 100644 index 0000000..08f352c --- /dev/null +++ b/maintain/0032.orders_fees_charge.js @@ -0,0 +1,17 @@ +/** + * Maintain mongo database + * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type + * + * + */ + + +exports.execute = function(db, script, callback){ + console.log(script,"Add order.payment.fees.charge default value of 2.9%"); + var logs="", count=0; + var orders=db.collection('orders'); + + orders.update({'payment.fees.charge':{$exists:false}}, {$set: {'payment.fees.charge': 0.029}}, { multi: true }); + + return callback(0,"orders have been updated"); +} diff --git a/models/categories.js b/models/categories.js index c7988f1..1793727 100644 --- a/models/categories.js +++ b/models/categories.js @@ -81,8 +81,14 @@ Categories.statics.create = function(cats, callback){ // create one Category var cat=((typeof cats) ==="string")?({name:cats}):(cats); cat.slug=cat.name.slug(); - var c =new Categories(cat); - c.save(callback); + Categories.findOne({slug:cat.slug}).select('_id').exec(function(err,duplicate) { + if(duplicate){ + return callback(new Error("Error duplicate category "+cat.name)); + } + var c =new Categories(cat); + c.save(callback); + + }); }; diff --git a/models/config.js b/models/config.js index d196a92..ea7f60d 100644 --- a/models/config.js +++ b/models/config.js @@ -29,12 +29,14 @@ var Config = new Schema({ }, // - // display welcome message + // display checkout message checkout:{ message:{en:String,fr:String,de:String}, active:{type:Boolean,default:false} }, + + // // display message on front diff --git a/models/lib/order.core.js b/models/lib/order.core.js index 7c06f45..219c49a 100644 --- a/models/lib/order.core.js +++ b/models/lib/order.core.js @@ -203,11 +203,26 @@ exports.coreCreate = function(oid,items,customer,shipping,paymentData, vendors,c } + // // ready to create one order var dborder =new Orders(order); + // + // fees dborder.payment.fees.shipping=dborder.getShippingPrice(); + dborder.payment.fees.charge=config.shared.order.gateway.reduce(function(p,gateway,i) { + if(gateway.label===paymentData.issuer){ + return gateway.fees; + } + return p; + }); + + + + // + // get discount offer by shops + dborder.computeDiscountAmountByShops(); // // update rank for this valid order @@ -230,7 +245,7 @@ exports.computeRankAndSave=function(cb){ sd.setHours(1,0,0,0) ed=new Date(sd.getTime()+86400000-3601000); - this.model('Orders').find({"shipping.when":{"$gte": sd, "$lt": ed}}).exec(function(err,orders){ + this.model('Orders').find({"shipping.when":{"$gte": sd, "$lt": ed}}).select('_id rank').exec(function(err,orders){ var newRank=0; for (var i = orders.length - 1; i >= 0; i--) { newRank=Math.max(newRank,orders[i].rank); diff --git a/models/lib/order.stats.js b/models/lib/order.stats.js index 0b5de3f..5a1457e 100644 --- a/models/lib/order.stats.js +++ b/models/lib/order.stats.js @@ -40,36 +40,82 @@ exports.favoriteProductsVsUsers=function(cb){ exports.ordersByUsers=function (filter,cb) { - var Orders=this, Users=db.model('Users'), results={}, match={}, today=new Date(); + var Orders=this, Users=db.model('Users'), results={}, match={'items.fulfillment.status':'fulfilled'}, today=new Date(); + + // + //$match:{ + // year:2015, + // 'items.fulfillment.status':'fulfilled', + // 'items.vendor':'herbaluna' + //} if(filter.year){ match.year=parseInt(filter.year)||match.year; } + if(filter.shop){ + match['items.vendor']=filter.shop; + } Orders.aggregate( - [ - { $match: { 'payment.status': 'paid' }}, - {$project:{ - month:{ $month:"$shipping.when"}, - week: { $week: "$shipping.when"}, - year: { $year: "$shipping.when" }, - items:1, - shipping:1, - email:1, - customer:1 - }}, - {$sort:{'shipping.when':-1}}, - {$match: match }, - {$group: - { - _id:"$email", - user:{$first:"$customer.name"}, - last:{$first:"$shipping.when"}, - count: { $sum: 1 } - } - }, - {$sort:{count:-1}} - ] + // TODO better stats + // { $match: { 'payment.status': 'paid' }}, + // {$project:{ + // oid:1, + // week: { $week: "$shipping.when"}, + // year: { $year: "$shipping.when" }, + // items:1, + // shipping:1, + // email:1, + // customer:1}}, + // {$sort:{'shipping.when':-1}}, + // {$unwind: '$items' }, + // {$match:match}, + // {$group: + // { + // _id:"$email", + // user:{$first:"$customer.name"}, + // last:{$first:"$shipping.when"}, + // first:{$last:"$shipping.when"}, + // orders: { $addToSet: "$oid" }, + // items:{$addToSet:{ + // oid:"$oid", + // week:"$week", + // year:"$year", + // when:"$shipping.when", + // sku:"$items.sku", + // title:"$items.title", + // finalprice:"$items.finalprice", + // quantity:"$items.quantity", + // vendor:"$items.vendor" + // }} + // } + // }, + // {$sort:{'last':-1}} + + + [ + { $match: { 'payment.status': 'paid' }}, + {$project:{ + month:{ $month:"$shipping.when"}, + week: { $week: "$shipping.when"}, + year: { $year: "$shipping.when" }, + items:1, + shipping:1, + email:1, + customer:1 + }}, + {$sort:{'shipping.when':-1}}, + {$match: match }, + {$group: + { + _id:"$email", + user:{$first:"$customer.name"}, + last:{$first:"$shipping.when"}, + count: { $sum: 1 } + } + }, + {$sort:{count:-1}} + ] ,function (err,stats) { if(err){ return cb(err); @@ -240,9 +286,247 @@ exports.getSellValueByYearAndWeek=function(query,cb){ }); }; +// +// new impl. to get CA by shop +// { +// query:{ +// month:10, << optional +// year:2016 +// }, +// header:{from,to }, +// shops:{ +// shop-slug:{amount,orders,fees,items,details:{name,slug}, discount} +// }, +// products:[{sku,count,amount,title,customers:[customer]}] +// } +exports.getCAByVendor=function(filter,cb) { + var today=new Date(), match={'items.fulfillment.status':'fulfilled',year:today.getFullYear()}; + // + // filter by month, year, thismonth,shop + filter=filter||{}; + if(filter.year){ + match.year=parseInt(filter.year); + } + if(filter.month){ + match.month=parseInt(filter.month); + } + if(filter.shop){ + match['items.vendor']=filter.shop; + if(Array.isArray(filter.shop)){ + match['items.vendor']={'$in':filter.shop}; + } + } + + + // + // only paid orders + this.aggregate([ + { $match: {$or:[{'payment.status': 'paid'},{'payment.status': 'invoice'}]} }, + {$project:{ + month:{ $month:"$shipping.when"}, + week: { $week: "$shipping.when"}, + year: { $year: "$shipping.when" }, + oid:1, + items:1, + email:1, + vendors:1 + }}, + { $unwind: '$vendors'}, + { $unwind: '$items'}, + { $match: match }, + + // + // join items.vendor === vendors.slug + { $redact:{ + $cond:[{$eq:["$items.vendor","$vendors.slug"]},"$$KEEP","$$PRUNE"]} + }, + {$sort:{'week':-1}}, + + // compute CA,FEES,DISCOUT and PRODUCTS grouped by [vendor,oid] + // {$cond:[{$eq:["$items.vendor","$vendors.slug"]},TRUE,FALSE]} + {$group:{ + _id:{oid:"$oid",vendor:"$items.vendor"}, + products:{$addToSet:{ + sku:"$items.sku", + title:"$items.title", + count:"$items.quantity", + amount:"$items.finalprice" + }}, + month:{$first:"$month"}, year:{$first:"$year"}, + items:{$sum:"$items.quantity"}, + amount:{$sum:"$items.finalprice"}, + name:{$first:"$vendors.name"}, + fees:{$first:"$vendors.fees"}, + discount:{$first:"$vendors.discount.finalAmount"} + } + }, + // + // CA,FEES,DISCOUT and PRODUCTS grouped by [month,year,vendor] + {$group:{ + _id:{ month:"$month", year:"$year", vendor:"$_id.vendor"}, + name:{$first:"$name"}, vendor:{$first:"$_id.vendor"}, + orders:{$addToSet:"$_id.oid"}, + items:{$sum:"$items"}, + products:{$addToSet:"$products"}, + amount:{$sum:"$amount"}, + discount:{$sum:"$discount"}, + fees:{$sum:{ $multiply: [ {$subtract:["$amount",{$ifNull:["$discount",0]}]}, "$fees" ]}}, + contractFees:{$addToSet:"$fees"}, + } + }, + {$sort:{'_id.year':-1,'_id.month':-1}} + ]).allowDiskUse(true).exec(function(err,results){ + if(err){ + return cb(err); + } + + + if(!results||!results.length){ + return cb(null,{}); + } + + + // + // round result + results.forEach(function(result) { + result.amount=parseFloat(result.amount.toFixed(2)); + result.discount=parseFloat(result.discount.toFixed(2)); + result.fees=parseFloat(result.fees.toFixed(2)); + result.products=_.flatten(result.products); + }); + + + // + // set output with the grouped format + if(filter.grouped){ + var report={shops:{},products:[]}, ca=0, items=0, orders=[], amount=0, discount=0; + var from=new Date();from.setDate(1);from.setHours(1,0,0,0);from.setMonth(0); + if(filter.month){from.setMonth(filter.month-1);} + if(filter.year){from.setFullYear(filter.year);} + + var to=new Date(from);to.setDate(from.daysInMonth());to.setHours(23,0,0,0); + if(!filter.month){to.setMonth(11)} + to.setDate(to.daysInMonth()); + + results.forEach(function(result) { + var i=0; + report.shops[result._id.vendor]=_.extend({},result); + delete report.shops[result._id.vendor]._id; + result.products.forEach(function(product) { + if(e=_.findWhere(report.products,{sku:product.sku})){ + e.count+=product.count; + e.amount+=product.amount; + return; + } + report.products.push(product); + }); + ca+=result.fees; + amount+=result.amount; + items+=result.items; + discount+=result.discount; + orders=_.union(result.orders,orders); + }); + + + + report.from=from; + report.to=to; + report.ca=parseFloat(ca.toFixed(2)); + report.discount=parseFloat(discount.toFixed(2)); + report.amount=parseFloat(amount.toFixed(2)); + report.items=items; + report.orders=orders; + + return cb(null,report); + + + } + + return cb(null,results); + }); +} + // // follow CA for shops exports.getCAByYearMonthAndVendor=function (filter,cb) { + filter=filter||{}; + filter.grouped=undefined; + this.getCAByVendor(filter,function(err, results) { + if(err){ + return cb(err); + } + + if(!results||!results.length){ + return cb(null,{}); + } + + var group={}, series_shops={}, axisX_date={}; + + // + // group amount CA by vendor + results.forEach(function(result){ + var stats={}; + + // + // build set of axisY + axisX_date[result._id.year+'.'+result._id.month]=Object.keys(axisX_date).length; + series_shops[result._id.vendor]=Object.keys(series_shops).length; + + // + // init group vendor with [year][month] + if(!group[result._id.year]){ + group[result._id.year]={}; + } + if(!group[result._id.year][result._id.month]){ + group[result._id.year][result._id.month]={}; + } + // {amount:0,fees:0,items:0,discount:0,contractFees:0} + group[result._id.year][result._id.month][result._id.vendor]=_.extend({},result); + delete group[result._id.year][result._id.month][result._id.vendor]._id; + + + }); + + + // + // compute CA for month + Object.keys(group).forEach(function (year) { + var amount=0,fees=0,discount=0,items=0; + // for each year + Object.keys(group[year]).forEach(function (month) { + // for each month + amount=0,fees=0,discount=0,items=0; + Object.keys(group[year][month]).forEach(function (slug) { + amount=amount+group[year][month][slug].amount; + fees=fees+group[year][month][slug].fees; + discount=discount+group[year][month][slug].discount; + items+=group[year][month][slug].items; + }); + group[year][month].amount=parseFloat(amount.toFixed(2)); + group[year][month].fees=parseFloat(fees.toFixed(2)); + group[year][month].discount=parseFloat(discount.toFixed(2)); + group[year][month].items=items; + + }); + }) + + // prepare axis + Object.keys(series_shops).forEach(function (shop,i) { + series_shops[shop]=i; + }); + + Object.keys(axisX_date).sortSeparatedAlphaNum().forEach(function (date,i) { + axisX_date[date]=i; + }); + + group.axis={ + x:axisX_date, + series:series_shops + } + return cb(undefined,group); + }) +}; +exports.getCAByYearMonthAndVendor_OFF=function (filter,cb) { var today=new Date(), match={'items.fulfillment.status':'fulfilled'}; // // filter by month, year, thismonth,shop @@ -283,6 +567,7 @@ exports.getCAByYearMonthAndVendor=function (filter,cb) { items:{$addToSet:{ oid:"$oid", sku:"$items.sku", + title:"$items.title", finalprice:"$items.finalprice", quantity:"$items.quantity", vendor:"$items.vendor", diff --git a/models/lib/order.utils.js b/models/lib/order.utils.js index b6cac1e..060a564 100644 --- a/models/lib/order.utils.js +++ b/models/lib/order.utils.js @@ -35,6 +35,7 @@ exports.print=function(order){ } if(self.vendors){ console.log("--- vendors ", self.vendors.map(function(v){ return v.slug}).join(',')); + console.log("--- discount ", self.vendors.map(function(v){ return v.discount.finalAmount}).join(',')); console.log("--- collected ", self.vendors.map(function(v){ return v.collected}).join(',')); } } @@ -111,6 +112,66 @@ var roundCHF=exports.roundCHF=function (value) { return parseFloat((Math.round(value*20)/20).toFixed(2)) } +// +// compute the discount for this order +exports.computeDiscountAmountByShops=function() { + var self=this; + // + // each vendors + this.vendors.forEach(function(vendor) { + // + //init discount + vendor.discount.finalprice=0; + + // + // this vendor offer no discount, get next one + if(!vendor.discount.threshold){ + return; + } + + // + // get amount from one vendor + var vendorAmount=0.0; + self.items.forEach(function(item) { + // and item.fulfillment.status!=='failure' + if (item.vendor===vendor.slug){ + vendorAmount+=item.finalprice; + } + }); + + // compute the dicount + var discountMagnitude=Math.floor(vendorAmount/vendor.discount.threshold); + vendor.discount.finalAmount=discountMagnitude*vendor.discount.amount; + + }); + +} + +// +// get amount of discount for this order +exports.getTotalDiscount=function(offset) { + var amount=0; + + this.vendors.forEach(function(vendor) { + amount+=(vendor.discount.finalAmount||0); + }); + + return amount; +} + +// +// stotal = items + shipping - total discount +// total = stotal + stotal*payment.fees +// WARNNG -- WARNNG -- WARNNG -- edit in all places +exports.getExtraDiscount=function() { + var total=this.getSubTotal(); + var shipping=this.getShippingPrice(); + var discount=this.getTotalDiscount(); + var fees=this.payment.fees.charge*(total+shipping-discount)+shipping; + return roundCHF(Math.max(discount-fees,0)); +}; + + exports.getShippingPrice=function(factor){ // // get the base of price depending the shipping sector @@ -125,6 +186,7 @@ exports.getShippingPrice=function(factor){ // get the base of price depending the shipping sector var distance=getShippingSectorPrice(this.shipping.postalCode); var price=config.shared.shipping.price[distance]; + var subtotal=this.getSubTotal(); // check if value exist, (after creation) @@ -143,12 +205,14 @@ exports.getShippingPrice=function(factor){ // implement 3) get free shipping! - if (config.shared.shipping.discountB&&this.getSubTotal()>=config.shared.shipping.discountB){ + if (config.shared.shipping.discountB && + subtotal>=config.shared.shipping.discountB){ return roundCHF(price-config.shared.shipping.priceB); } // implement 3) get half shipping! - else if (config.shared.shipping.discountA&&this.getSubTotal()>=config.shared.shipping.discountA){ + else if (config.shared.shipping.discountA && + subtotal>=config.shared.shipping.discountA){ return roundCHF(price-config.shared.shipping.priceA); } @@ -176,15 +240,15 @@ exports.getTotalPrice=function(factor){ // add shipping fees (10CHF) total+=this.getShippingPrice(); + + // + // remove discout offer by shop + // total to pay + total-=this.getTotalDiscount(); + // // add gateway fees - for (var gateway in config.shared.order.gateway){ - gateway=config.shared.order.gateway[gateway] - if (gateway.label===this.payment.issuer){ - total+=total*gateway.fees; - break; - } - } + total+=this.payment.fees.charge*total; // add mul factor factor&&(total*=factor); diff --git a/models/order.js b/models/order.js index 96ff6f1..2cf88f0 100644 --- a/models/order.js +++ b/models/order.js @@ -85,12 +85,6 @@ var Orders = new Schema({ shipping:{type:Number} }, - /* discout is an amount offer by a shop */ - discount:[{ - amount:Number, - vendor:{type:String} - }], - /* for security reason transaction data are encrypted */ transaction:{type:String,select:false} }, @@ -153,7 +147,16 @@ var Orders = new Schema({ lat:{type:Number, required: false}, lng:{type:Number, required: false} }, - collected:{type:Boolean,default:false} + collected:{type:Boolean,default:false}, + // + // you can see values only when uid is order.owner, shop.owner, or admin + // amount & threshold & finalAmount & are saved for security reason + discount:{ + amount:{type:Number,min:0,default:0,select:true}, + threshold:{type: Number,min:0,select:true}, + finalAmount:{type: Number,min:0,default:0,select:true} + } + }], shipping:{ @@ -187,6 +190,9 @@ Orders.statics.printInfo=utils.printInfo; Orders.statics.prepare=utils.prepare; Orders.methods.equalItem=utils.equalItem; Orders.methods.getShippingPrice=utils.getShippingPrice; +Orders.methods.computeDiscountAmountByShops=utils.computeDiscountAmountByShops; +Orders.methods.getTotalDiscount=utils.getTotalDiscount; +Orders.methods.getExtraDiscount=utils.getExtraDiscount; Orders.methods.getTotalPrice=utils.getTotalPrice; Orders.methods.getSubTotal=utils.getSubTotal; Orders.methods.getDateString=utils.getDateString; @@ -224,6 +230,7 @@ Orders.statics.convertOrdersToRepportForShop=format.convertOrdersToRepportForSho Orders.statics.getStatsByOrder=stats.getStatsByOrder; Orders.statics.favoriteProductsVsUsers=stats.favoriteProductsVsUsers; Orders.statics.getSellValueByYearAndWeek=stats.getSellValueByYearAndWeek; +Orders.statics.getCAByVendor=stats.getCAByVendor; Orders.statics.getCAByYearMonthAndVendor=stats.getCAByYearMonthAndVendor; Orders.statics.ordersByPostalVsUsersByPostal=stats.ordersByPostalVsUsersByPostal; Orders.statics.ordersByUsers=stats.ordersByUsers; @@ -352,9 +359,16 @@ Orders.statics.checkItem=function(shipping, item, product, cb){ address:address, fees:product.vendor.account.fees, geo:geo, - discount:product.vendor.discount + discount:{} }; + // + // case of discount + if(product.vendor.discount.active){ + vendor.discount.threshold=product.vendor.discount.threshold; + vendor.discount.amount=product.vendor.discount.amount; + } + // // duplicate fees to simplify repport item.fees=product.vendor.account.fees; diff --git a/models/products.js b/models/products.js index 568fcd6..8e416c7 100644 --- a/models/products.js +++ b/models/products.js @@ -108,7 +108,29 @@ var Product = new Schema({ }); +Product.methods.print=function(product){ + var self=product||this; + console.log("-- SKU ", self.sku); + console.log("--- title ", self.title,self.slug); + console.log("--- price ", self.pricing.price,self.pricing.stock,self.pricing.part); + if(self.categories.name){ + console.log("--- category ", self.categories.slug); + }else{ + console.log("--- category ", self.categories); + } + if(self.vendor.urlpath){ + console.log("--- vendor ", self.vendor.urlpath); + console.log("--- vendor.discount", self.vendor.discount); + }else{ + console.log("--- vendor ", self.vendor); + } + if(self.variants.length){ + self.variants.forEach(function(variant) { + console.log("--- variant ", variant.title); + }) + } +}; // // API @@ -587,7 +609,12 @@ Product.statics.findByCriteria = function(criteria, callback){ var nextShippingDays=Date.fullWeekShippingDays(8); // specify a custom date if(criteria.when){ - nextShippingDays=[new Date(criteria.when)]; + // FIXME what if date is not valid? + if(['on',true,'true','next'].indexOf(criteria.when)>-1){ + nextShippingDays=[nextShippingDays[0]]; + }else{ + nextShippingDays=[new Date(Date.parse(criteria.when))]; + } } Shops.findAvailable(nextShippingDays).then(function(available) { @@ -784,6 +811,7 @@ Product.statics.findByCriteria = function(criteria, callback){ // }); // }; + Product.set('autoIndex', config.mongo.ensureIndex); exports.Products = mongoose.model('Products', Product); exports.Manufacturers = mongoose.model('Manufacturers', Manufacturer); diff --git a/models/shops.js b/models/shops.js index 1218cd5..c048b1e 100644 --- a/models/shops.js +++ b/models/shops.js @@ -24,6 +24,8 @@ var Shops = new Schema({ owner:{ type: String, required: false }, bg:{ type: String, required: false }, fg:{ type: String, required: false }, + logo:{type: String, required: false, maxlength:500 }, + gallery:[{type: String, required: false, maxlength:500 }], source:{ type: String, required: false } }, diff --git a/models/users.js b/models/users.js index 6a2d4cc..867f2da 100644 --- a/models/users.js +++ b/models/users.js @@ -84,7 +84,7 @@ validate.postal = function (value) { addresses: [{ name: { type: String, required : true, lowercase: true, trim: true }, - note: { type: String, trim: true }, + note: { type: String, trim: true, default:"" }, floor: { type: String, trim: true, required : true }, streetAdress: { type: String, required : true, lowercase: true, trim: true }, region: { type: String, required : true, trim: true, default:"Genève", enum: EnumRegion }, @@ -181,6 +181,8 @@ UserSchema.statics.findOrCreate=function(u,callback){ u.id=u['email.address'].hash() u["email.status"]=true; + u['shops']=[]; + u['payments']=[]; } var newuser=new Users(u); @@ -539,6 +541,8 @@ UserSchema.statics.register = function(email, first, last, password, confirm, ex }, email:{address:email,status:new Date()}, provider:"local", + shops:[], + payments:[], password:password, created:new Date() }); @@ -854,7 +858,7 @@ UserSchema.statics.deletePayment=function(id, alias,callback){ .fail(function(err) { // // error is tracked but card is always removed! - bus.emit('system.message',"[karibou-danger] remove alias: "+err.message,{error:err,user:id, alias:alias}); + bus.emit('system.message',"[karibou-danger] remove alias: "+err.message,{error:err,user:id, alias:JSON.stringify(p)}); return; }) }); diff --git a/test/api.orders.repport.js b/test/api.orders.report.js similarity index 98% rename from test/api.orders.repport.js rename to test/api.orders.report.js index 6af4dd7..1b206ce 100644 --- a/test/api.orders.repport.js +++ b/test/api.orders.report.js @@ -13,7 +13,7 @@ describe("api.orders.find", function(){ before(function(done){ dbtools.clean(function(e){ - dbtools.load(["../fixtures/Users.js","../fixtures/Orders.repport.js"],db,function(err){ + dbtools.load(["../fixtures/Users.js","../fixtures/Orders.report.js"],db,function(err){ should.not.exist(err); // Orders.printInfo() diff --git a/test/api.users.js b/test/api.users.js index f979345..0ef90be 100644 --- a/test/api.users.js +++ b/test/api.users.js @@ -91,6 +91,7 @@ describe("api.users", function(){ res.body.email.address.should.equal("evaleto@gluck.com"); should.not.exist(res.body.hash) should.not.exist(res.body.salt) + // token = res.body.token; cookie = res.headers['set-cookie']; user=res.body; //res.headers.location.should.equal('/'); @@ -101,6 +102,7 @@ describe("api.users", function(){ it('GET /v1/users/me should return 200',function(done){ request(app) .get('/v1/users/me') + // .set('Authorization', 'Bearer ' + token) .set('cookie', cookie) .end(function(err,res){ res.should.have.status(200); diff --git a/test/category.js b/test/category.js index 118fa0b..27df39a 100644 --- a/test/category.js +++ b/test/category.js @@ -55,7 +55,7 @@ describe("Categories", function(){ type:"Pouet" },function(err,m){ should.exist(err); - err.message.should.equal("Categories validation failed") + err.message.should.equal("Error duplicate category Olivier") done(); }); diff --git a/test/fixtures/Orders.find.js b/test/fixtures/Orders.find.js index e6174ea..2b02211 100644 --- a/test/fixtures/Orders.find.js +++ b/test/fixtures/Orders.find.js @@ -63,6 +63,9 @@ exports.Orders=[ slug: "un-autre-shop", name: "un autre shop", address: "TODO", + discount:{ + finaleAmount:0 + } } ], @@ -117,6 +120,9 @@ exports.Orders=[ slug: "super-shop", name: "super shop", address: "TODO", + discount:{ + finaleAmount:0 + } }, { /* shop available !=true */ @@ -124,6 +130,9 @@ exports.Orders=[ slug: "un-autre-shop", name: "un autre shop", address: "TODO", + discount:{ + finaleAmount:0 + } } ], /* items */ @@ -222,6 +231,9 @@ exports.Orders=[ slug: "un-autre-shop", name: "Un autre shop", address: "TODO", + discount:{ + finaleAmount:0 + } }, { /*shop status !=true */ @@ -229,7 +241,11 @@ exports.Orders=[ slug: "mon-shop", name: "mon shop", address: "TODO", + discount:{ + finaleAmount:0 + } } + ], /* items */ items: [ @@ -328,6 +344,9 @@ exports.Orders=[ slug: "un-autre-shop", name: "Un autre shop", address: "TODO", + discount:{ + finaleAmount:0 + } }, { /*shop status !=true */ @@ -335,6 +354,9 @@ exports.Orders=[ slug: "mon-shop", name: "mon shop", address: "TODO", + discount:{ + finaleAmount:0 + } } ], /* items */ @@ -434,6 +456,9 @@ exports.Orders=[ slug: "un-autre-shop", name: "Un autre shop", address: "TODO", + discount:{ + finaleAmount:0 + } }, { /*shop status !=true */ @@ -441,6 +466,9 @@ exports.Orders=[ slug: "mon-shop", name: "mon shop", address: "TODO", + discount:{ + finaleAmount:0 + } } ], /* items */ @@ -513,6 +541,9 @@ exports.Shops=[{ info:{ detailledOrder:true }, + discount:{ + active:false + }, available:{ active:false, weekdays:[0,1,2,3,4,5,6] @@ -529,6 +560,9 @@ exports.Shops=[{ urlpath:"mon-shop", catalog:c.Categories[0]._id, owner:u.Users[1]._id, //evaleto@gmail.com + discount:{ + active:false + }, photo:{ bg:"http://image.truc.io/bg-01123.jp", fg:"http://image.truc.io/fg-01123.jp" @@ -552,6 +586,9 @@ exports.Shops=[{ active:false, weekdays:[0,1,2,3,4,5,6] }, + discount:{ + active:false + }, photo:{ bg:"http://image.truc.io/bg-01123.jp", fg:"http://image.truc.io/fg-01123.jp" @@ -568,6 +605,9 @@ exports.Shops=[{ bg:"http://image.truc.io/bg-01123.jp", fg:"http://image.truc.io/fg-01123.jp" }, + discount:{ + active:false + }, available:{ active:false, weekdays:[0,1,2,3,4,5,6] diff --git a/test/fixtures/Orders.payment.capture.js b/test/fixtures/Orders.payment.capture.js index a06e5e3..4ecfd27 100644 --- a/test/fixtures/Orders.payment.capture.js +++ b/test/fixtures/Orders.payment.capture.js @@ -36,7 +36,10 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"voided" + status:"voided", + fees:{ + charge:0.02 + } }, @@ -87,7 +90,10 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"refunded" + status:"refunded", + fees:{ + charge:0.02 + } }, @@ -138,7 +144,10 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"voided" + status:"voided", + fees:{ + charge:0.02 + } }, @@ -190,7 +199,10 @@ exports.Orders=[ issuer: "invoice", alias:((u.Users[1].id+'invoice').hash().crypt()), transaction:'yes', - status:"authorized" + status:"authorized", + fees:{ + charge:0.0 + } }, fulfillments: { @@ -297,7 +309,10 @@ exports.Orders=[ number:'98xxxxxxx4123', alias:((u.Users[1].id+'').hash().crypt()), transaction:'yes', - status:"authorized" + status:"authorized", + fees:{ + charge:0.02 + } }, fulfillments: { @@ -403,7 +418,10 @@ exports.Orders=[ issuer: "visa", number:'98xxxxxxx4123', alias:'0123456789012012345678901201234567890120123456789012', - status:"authorized" + status:"authorized", + fees:{ + charge:0.029 + } }, fulfillments: { @@ -509,7 +527,10 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"authorized" + status:"authorized", + fees:{ + charge:0.02 + } }, fulfillments: { @@ -615,7 +636,10 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"pending" + status:"pending", + fees:{ + charge:0.02 + } }, fulfillments: { @@ -709,6 +733,7 @@ exports.Orders=[ } ]; + // // ------------------------ SHOPS -------------------------- // diff --git a/test/fixtures/Orders.payment.js b/test/fixtures/Orders.payment.js index 35637bc..8d3d052 100644 --- a/test/fixtures/Orders.payment.js +++ b/test/fixtures/Orders.payment.js @@ -36,7 +36,8 @@ exports.Orders=[ issuer: "invoice", number:'98xxxxxxx4123', alias:((u.Users[1].id+'invoice').hash().crypt()), - status:"voided" + status:"voided", + fees:{charge:0.0} }, @@ -88,7 +89,8 @@ exports.Orders=[ number:'98xxxxxxx4123', expiry:'08/2015', alias:((u.Users[1].id+'invoice').hash().crypt()), - status:"pending" + status:"pending", + fees:{charge:0.0} }, @@ -139,7 +141,8 @@ exports.Orders=[ issuer: "invoice", number:'98xxxxxxx4123', alias:((u.Users[1].id+'invoice').hash().crypt()), - status:"voided" + status:"voided", + fees:{charge:0.0} }, @@ -191,7 +194,8 @@ exports.Orders=[ number:'98xxxxxxx4123', alias:((u.Users[1].id+'').hash().crypt()), transaction:2000007, - status:"authorized" + status:"authorized", + fees:{charge:0.02} }, fulfillments: { @@ -297,7 +301,8 @@ exports.Orders=[ issuer: "visa", number:'98xxxxxxx4123', alias:((u.Users[1].id+'').hash().crypt()), - status:"authorized" + status:"authorized", + fees:{charge:0.029} }, fulfillments: { @@ -403,7 +408,8 @@ exports.Orders=[ issuer: "invoice", number:'98xxxxxxx4123', alias:((u.Users[1].id+'invoice').hash().crypt()), - status:"authorized" + status:"authorized", + fees:{charge:0.0} }, fulfillments: { @@ -509,7 +515,8 @@ exports.Orders=[ issuer: "invoice", number:'98xxxxxxx4123', alias:((u.Users[1].id+'invoice').hash().crypt()), - status:"pending" + status:"pending", + fees:{charge:0.0} }, fulfillments: { diff --git a/test/fixtures/Orders.price.js b/test/fixtures/Orders.price.js index 8bdfa23..67eca3b 100644 --- a/test/fixtures/Orders.price.js +++ b/test/fixtures/Orders.price.js @@ -36,7 +36,7 @@ exports.Orders=[ number:'98xxxxxxx4123', alias:'01234567890', status:"voided", - fees:{shipping:0} + fees:{shipping:0, charge:0.029} }, /* shipping adresse*/ @@ -108,7 +108,8 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"pending" + status:"pending", + fees:{charge:0.02} }, fulfillments: { @@ -186,7 +187,8 @@ exports.Orders=[ issuer: "mastercard", number:'98xxxxxxx4123', alias:'01234567890', - status:"paid" + status:"paid", + fees:{charge:0.029} }, fulfillments: { @@ -279,7 +281,8 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"paid" + status:"paid", + fees:{charge:0.02} }, fulfillments: { @@ -371,7 +374,8 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"paid" + status:"paid", + fees:{charge:0.02} }, fulfillments: { @@ -477,7 +481,8 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"paid" + status:"paid", + fees:{charge:0.02} }, fulfillments: { diff --git a/test/fixtures/Orders.price.merchant.js b/test/fixtures/Orders.price.merchant.js index a125187..97ea3fb 100644 --- a/test/fixtures/Orders.price.merchant.js +++ b/test/fixtures/Orders.price.merchant.js @@ -37,7 +37,7 @@ exports.Orders=[ number:'98xxxxxxx4123', alias:'01234567890', status:"voided", - fees:{shipping:0} + fees:{shipping:0, charge:0.029} }, /* shipping adresse*/ @@ -109,7 +109,8 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"pending" + status:"pending", + fees:{charge:0.02} }, fulfillments: { @@ -187,7 +188,8 @@ exports.Orders=[ issuer: "mastercard", number:'98xxxxxxx4123', alias:'01234567890', - status:"paid" + status:"paid", + fees:{charge:0.029} }, fulfillments: { @@ -280,7 +282,8 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"paid" + status:"paid", + fees:{charge:0.02} }, fulfillments: { @@ -372,7 +375,8 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"paid" + status:"paid", + fees:{charge:0.02} }, fulfillments: { @@ -478,7 +482,8 @@ exports.Orders=[ issuer: "tester", number:'98xxxxxxx4123', alias:'01234567890', - status:"paid" + status:"paid", + fees:{charge:0.02} }, fulfillments: { diff --git a/test/fixtures/Orders.report.022016.js b/test/fixtures/Orders.report.022016.js new file mode 100644 index 0000000..dcc8d10 --- /dev/null +++ b/test/fixtures/Orders.report.022016.js @@ -0,0 +1,4071 @@ +var ObjectId = require('mongodb').ObjectID; +var c=require('./Categories'); +var u=require('./Users'); +var orders = require('mongoose').model('Orders'); + +// this fixture focus on order with +// - different dates (today, next shipping day, next week), +// - config.shared.financialstatus ("pending","authorized","partially_paid","paid", "partially_refunded" ...) +// - config.shared.cancelreason ("customer", "fraud", "inventory", "other") +// - config.shared.status ("fulfilled","partial","fulfilled", "shipped","failure") +// +// build orders with +// - 2 users +// - all products, stock, shop, user ... are available +// - + +var oneweek=orders.findOneWeekOfShippingDay(); +var firstDayOfMonth=orders.findCurrentShippingDay(); +var lastDayOfMonth=new Date(firstDayOfMonth); +var customerDay=oneweek[0]; + +var passedday=new Date(customerDay.getTime()-86400000*7) + +lastDayOfMonth.setDate(lastDayOfMonth.daysInMonth()); +lastDayOfMonth.setHours(22,0,0,0); + +firstDayOfMonth.setDate(1); +firstDayOfMonth.setHours(16,0,0,0); + +exports.Orders=[ +{ + "oid": 2000606, + "email": "fabio.loverso@lacite.info", + "payment": { + "alias": "1ee6598575d58146b8f2930cb27c7bf343fd7c7e5b00cce546de64505b9a660caadd4023b2d479737d46dc4c56329fc0f218d6b8c9f76385beb44bb112908c7c42aad08d2e2df87de23e60d9e91de38c0e0e0e0e", + "number": "xxxx-xxxx-xxxx-9908", + "issuer": "visa", + "expiry": "2/2017", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 72.85 the Sat Jan 17 1970 20:54:32 GMT+0100 (CET)", + "capture 72.85 the Sat Jan 17 1970 20:54:32 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "d6dd5123617e4baf299c42508d401fd11293afc8b058d3ef60159b526ed73b550e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-01-29T13:00:37.252Z", + "closed": "2016-02-02T18:08:06.155Z", + "items": [ + { + "title": "Viande séchée de Genève", + "sku": 1000030, + "price": 8.6, + "finalprice": 8.6, + "vendor": "les-fromages-de-gaetan", + "part": "~100gr", + "quantity": 1, + "category": "Boucherie et charcuterie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "lo verso fabio", + "note": "Interphone", + "streetAdress": "15b, rue des noirettes", + "floor": "2", + "postalCode": "1227", + "region": "Carouge,GE", + "when": "2016-02-02T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.18884449999999, + "lng": 6.135447999999999 + }, + "bags": 1 + }, + "sum": 8.6, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000607, + "email": "elidesign@infomaniak.ch", + "payment": { + "alias": "45078aa35123c6977224430a5ff762631eb8a9673d98c39c3f7f885b04a6a132c37ccca8e1fd3dde564337be6341abbb3b876f333c9d9e3acb7e83cfa5010cda1caae01dd2cbb610569d3055c8b8c4bc0e0e0e0e", + "number": "xxxx-xxxx-xxxx-1337", + "issuer": "mastercard", + "expiry": "9/2018", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 51.2 the Sat Jan 17 1970 20:56:16 GMT+0100 (CET)", + "capture 51.2 the Sat Jan 17 1970 20:56:16 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "40cede733e46d457f2c72a51ee6f41cfe1d2157a4f8f443db85abcbd64789f000e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-01-30T18:02:50.882Z", + "closed": "2016-02-02T18:08:09.024Z", + "items": [ + { + "title": "Gâteau à l’orange", + "sku": 1000309, + "price": 4, + "finalprice": 4, + "vendor": "purogusto", + "part": "1pce", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Parmigiana d’aubergines", + "sku": 1000310, + "price": 11, + "finalprice": 11, + "vendor": "purogusto", + "part": "250gr", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Quiche salée", + "sku": 1000316, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "1 pce", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "ascari varady elisabeth", + "note": "--- La livraison : Mme ASCARI GRAZIELLA le code d'entrée après 17h00 - 7356", + "streetAdress": "20 a avenue du bouchet", + "floor": "3", + "postalCode": "1209", + "region": "Genève", + "when": "2016-02-02T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2185013, + "lng": 6.122540799999999 + }, + "bags": 1 + }, + "sum": 21, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000609, + "email": "jeromebaudry23@yahoo.fr", + "payment": { + "alias": "051e533e83cee69ccde967a1806df4bc624c83ab0b9cea5c268ed92f20bcd51f1c5f3374e16f9e6f88e5a1220a42f36b597da6b1973e9cdcb4b7e43e68c7b351c8d886a157d7d9fe2df40cc7e130bab40e0e0e0e", + "number": "xxxx-xxxx-xxxx-8598", + "issuer": "visa", + "expiry": "11/2018", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 102.05 the Sat Jan 17 1970 20:57:11 GMT+0100 (CET)", + "capture 102.05 the Sat Jan 17 1970 20:57:11 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "8ef79748c85d075f0665bd5c395360d0dc66678fca62ac4b0933da05056a73280e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-01-31T09:16:13.499Z", + "closed": "2016-02-02T18:08:11.812Z", + "items": [ + { + "title": "Saint-félicien affiné", + "sku": 1000206, + "price": 7.4, + "finalprice": 7.4, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Le Maréchal", + "sku": 1000401, + "price": 8.4, + "finalprice": 9.3, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Bleu de Fribourg", + "sku": 1000403, + "price": 6.6, + "finalprice": 6.6, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "colboc emmanuel", + "note": "code 9660, 2e gauche", + "streetAdress": "rue du vieux-billard 10", + "floor": "2", + "postalCode": "1205", + "region": "Genève", + "when": "2016-02-02T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2005498, + "lng": 6.1386011 + }, + "bags": 2 + }, + "sum": 23.300000000000004, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000610, + "email": "consoli.fabio@gmail.com", + "payment": { + "alias": "9ac7ba5c4fab44542772afa1d24de39ff8c7dc9d83130b937eba4b597127467a2e59e5d6b628bfacfd5dfe40f29e63c25f9339a591a517732c236b7a961f65fdaddbd93984a57f4b833c139058f57f720e0e0e0e", + "number": "xxxx-xxxx-xxxx-2331", + "issuer": "visa", + "expiry": "2/2018", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 110.8 the Sat Jan 17 1970 20:57:43 GMT+0100 (CET)", + "capture 110.8 the Sat Jan 17 1970 20:57:43 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "2d970eaa8a2d1c9f93c8dfeb8a07202945aa533dae5f2f8f7a7ad473f302d4e50e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-01-31T17:58:10.745Z", + "closed": "2016-02-02T18:08:14.542Z", + "items": [ + { + "title": "Gruyère fruité (16 mois d'affinage)", + "sku": 1000024, + "price": 7.35, + "finalprice": 7.35, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Viande séchée de Genève", + "sku": 1000030, + "price": 8.6, + "finalprice": 8.6, + "vendor": "les-fromages-de-gaetan", + "part": "~100gr", + "quantity": 1, + "category": "Boucherie et charcuterie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "consoli fabio", + "note": "code: #7258", + "streetAdress": "rue de carouge 72", + "floor": "5", + "postalCode": "1205", + "region": "Genève", + "when": "2016-02-02T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1925523, + "lng": 6.1437018 + }, + "bags": 1 + }, + "sum": 15.95, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000611, + "email": "michele.terrier@hotmail.ch", + "payment": { + "alias": "bb3ddae9484bf3071571640bb378858f25383fdcc407871b3f5a432de1e5f482d1259cf65c4c34aea26de5d915a6f13912a015d252868622818103f53ae4cad859f08fcc411d05a2c5279c807114458d0e0e0e0e", + "number": "xxxx-xxxx-xxxx-4279", + "issuer": "mastercard", + "expiry": "5/2016", + "fees": { + "shipping": 7.5 + }, + "logs": [ + "authorized amount 197.95 the Sat Jan 17 1970 20:57:45 GMT+0100 (CET)", + "capture 197.95 the Sat Jan 17 1970 20:57:45 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "4b1987eba03955f1764c287e0b5b3de110ebffc84789ad74e0e70961b2fcc9720e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-01-31T18:35:00.221Z", + "closed": "2016-02-02T18:08:17.607Z", + "items": [ + { + "title": "Petit caprèse au chocolat noir", + "sku": 1000306, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "2pce", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Gâteau à l’orange", + "sku": 1000309, + "price": 4, + "finalprice": 8, + "vendor": "purogusto", + "part": "1pce", + "quantity": 2, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Quiche salée", + "sku": 1000316, + "price": 6, + "finalprice": 12, + "vendor": "purogusto", + "part": "1 pce", + "quantity": 2, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pate à tartiner chocolat noir/noisette", + "sku": 1000436, + "price": 15, + "finalprice": 15, + "vendor": "purogusto", + "part": "200gr", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pain d’épices aux trois poivres", + "sku": 1000439, + "price": 12, + "finalprice": 12, + "vendor": "purogusto", + "part": "450gr", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "pharmacie des bergues", + "note": "Livrer directement à la pharmacie svp", + "streetAdress": "25 quai des bergues", + "floor": "Arcade", + "postalCode": "1201", + "region": "Genève", + "when": "2016-02-02T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2064842, + "lng": 6.145340099999999 + }, + "bags": 2 + }, + "sum": 53, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000612, + "email": "evaleto@gmail.com", + "payment": { + "alias": "fabdfe0d9a0b11b93b41af91de3a19f1be80a97f4c6a871a918c91f40d920876cf26fbd9524f3cb1650f04dd8e14151c925459d45c47051723cbf4ba0939926fae771ba981622fd1b4db2994020ed4540e0e0e0e", + "number": "xxxx-xxxx-xxxx-0347", + "issuer": "visa", + "expiry": "8/2016", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 145 the Sat Jan 17 1970 20:57:53 GMT+0100 (CET)", + "capture 145 the Sat Jan 17 1970 20:57:53 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "2e8b8352508341c279e9805917b499775c0718cba5306e929001ee5e65b1d6950e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-01-31T20:54:49.539Z", + "closed": "2016-02-02T18:08:19.914Z", + "items": [ + { + "title": "Beurre en motte", + "sku": 1000018, + "price": 5, + "finalprice": 5, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Petit camembert", + "sku": 1000027, + "price": 6.5, + "finalprice": 6.5, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Tomme de Savoie AOC", + "sku": 1000029, + "price": 5.6, + "finalprice": 6.3, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Le Maréchal", + "sku": 1000401, + "price": 8.4, + "finalprice": 8.4, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Tomme fleurette", + "sku": 1000404, + "price": 5.1, + "finalprice": 5.1, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "evalet olivier", + "note": "code 1956", + "streetAdress": "34 route chêne", + "floor": "2", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-02T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1997473, + "lng": 6.1692497 + }, + "bags": 2 + }, + "sum": 31.300000000000004, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000615, + "email": "fauziah_yusoff@yahoo.fr", + "payment": { + "alias": "468e332b3065962edc22d8dc299ba127411ac0905bf5f13e22ad7efa9c64157d0a649fb5501de2ad388264c5064ceccff033c18a0c8bb26994af56ce0b9b63541969728f4eeaa26fdf2168e2318a0c120e0e0e0e", + "number": "xxxx-xxxx-xxxx-1406", + "issuer": "visa", + "expiry": "12/2017", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 88.6 the Sat Jan 17 1970 21:00:29 GMT+0100 (CET)", + "capture 88.6 the Sat Jan 17 1970 21:00:29 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "77b0d03bc2bdfcccba31a607b56a326b6bd636e4c8b1b8e3246b5a0ffb77f8bc0e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-02T16:11:23.624Z", + "closed": "2016-02-05T15:38:01.008Z", + "items": [ + { + "title": "Pain naturellement sans gluten", + "sku": 1000313, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "~900gr", + "quantity": 1, + "category": "Boulangerie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "gardaz fauziah", + "note": "Il faut passer la porte vitrée et aller au bout de la coursive extérieure, à la dernière porte.", + "streetAdress": "rue des délices 33", + "floor": "5 ème", + "postalCode": "1203", + "region": "Genève", + "when": "2016-02-05T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2081242, + "lng": 6.1346232 + }, + "bags": 2 + }, + "sum": 6, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000616, + "email": "atank@infomaniak.ch", + "payment": { + "alias": "6f873b28c126d508e9f5402fa96b7446106bbfd31ce6c72a1050edab602bbea70a2858adde50b3cc5a4f580bc44d81426baab0dbe40cb611b4435dc6c58e0af976c97934fe487ba4ac2c3470ffa10a780e0e0e0e", + "number": "xxxx-xxxx-xxxx-8674", + "issuer": "mastercard", + "expiry": "4/2016", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 72.45 the Sat Jan 17 1970 21:00:45 GMT+0100 (CET)", + "capture 72.45 the Sat Jan 17 1970 21:00:45 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "1734b3a56e762c8b86d858b054ee3e6ec0876447351845fd18f05a33dfdce7760e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-02T20:40:54.412Z", + "closed": "2016-02-05T15:38:03.411Z", + "items": [ + { + "title": "Viande séchée de Genève", + "sku": 1000030, + "price": 8.6, + "finalprice": 8.6, + "vendor": "les-fromages-de-gaetan", + "part": "~100gr", + "quantity": 1, + "category": "Boucherie et charcuterie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pain naturellement sans gluten", + "sku": 1000313, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "~900gr", + "quantity": 1, + "category": "Boulangerie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "tank anouk", + "note": "code : 1009", + "streetAdress": "48 rte de malagnou", + "floor": "5e", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-05T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1966198, + "lng": 6.162958199999999 + }, + "bags": 2 + }, + "sum": 14.6, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000617, + "email": "l.e.n.a@bluewin.ch", + "payment": { + "alias": "42631feb0d57a45413ffd1c494095df08da279789783d32f7f1527af2da352fdd58dc1be82b7348a1aa9114d6a41b439dc19d34d82d5f815cdc4b6466ba954ed15d3dde29ca92a4651fdd325da4525dc0e0e0e0e", + "number": "xxxx-xxxx-xxxx-2572", + "issuer": "mastercard", + "expiry": "10/2017", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 96.55 the Sat Jan 17 1970 21:00:54 GMT+0100 (CET)", + "capture 96.55 the Sat Jan 17 1970 21:00:54 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "4082add094d8165bcdf4878fead1a4641e6927eb530bd7be9331c87727e966630e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-02T23:04:40.640Z", + "closed": "2016-02-05T15:38:05.820Z", + "items": [ + { + "title": "Gruyère vieux (26 mois d'affinage)", + "sku": 1000025, + "price": 7.35, + "finalprice": 7.35, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Tomme de Savoie AOC", + "sku": 1000029, + "price": 5.6, + "finalprice": 7, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Mothais sur feuille", + "sku": 1000400, + "price": 7.4, + "finalprice": 7.4, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "strasser léna", + "note": "code 62354# (si pas là déposer devant la porte, merci)", + "streetAdress": "rue de l'encyclopédie 20", + "floor": "5eme", + "postalCode": "1201", + "region": "Genève", + "when": "2016-02-05T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2062623, + "lng": 6.1342436 + }, + "bags": 2 + }, + "sum": 21.75, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000618, + "email": "annecanepa@gmail.com", + "payment": { + "alias": "e4579fa6dd094f952d055b39f0573a4f89926e8ae304e1cc3dabe47cf4ade8b9c31fa3e164059412a9d321725d8098faf853e1a960078f2e3f401d7b67c3bccfcf51071f8430ec0bb5987e50b444e26d0e0e0e0e", + "number": "xxxx-xxxx-xxxx-0119", + "issuer": "visa", + "expiry": "6/2016", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 128.7 the Sat Jan 17 1970 21:01:52 GMT+0100 (CET)", + "capture 128.7 the Sat Jan 17 1970 21:01:52 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "9d91941d3491e6eee8b176a992979da64e0f7dbfbbd5170be14e2debb6be55920e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-03T15:07:58.341Z", + "closed": "2016-02-05T15:38:08.300Z", + "items": [ + { + "title": "Tomme de Savoie AOC", + "sku": 1000029, + "price": 5.6, + "finalprice": 5.6, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Viande séchée de Genève", + "sku": 1000030, + "price": 8.6, + "finalprice": 8.6, + "vendor": "les-fromages-de-gaetan", + "part": "~100gr", + "quantity": 1, + "category": "Boucherie et charcuterie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "canepa anne", + "note": "appartement 52A", + "streetAdress": "118 route de florissant", + "floor": "5", + "postalCode": "1206", + "region": "Genève", + "when": "2016-02-05T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1899536, + "lng": 6.1663951 + }, + "bags": 1 + }, + "sum": 14.2, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000619, + "email": "evaleto@gmail.com", + "payment": { + "alias": "fabdfe0d9a0b11b93b41af91de3a19f1be80a97f4c6a871a918c91f40d920876cf26fbd9524f3cb1650f04dd8e14151c925459d45c47051723cbf4ba0939926fae771ba981622fd1b4db2994020ed4540e0e0e0e", + "number": "xxxx-xxxx-xxxx-0347", + "issuer": "visa", + "expiry": "8/2016", + "fees": { + "shipping": 0 + }, + "logs": [ + "authorized amount 122.45 the Sat Jan 17 1970 21:02:14 GMT+0100 (CET)", + "capture 122.45 the Sat Jan 17 1970 21:02:14 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "8420307e7f750f61b845efc8120c68bd64ac3bc8d8d5cafc847f1be76de190550e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-03T21:22:41.735Z", + "closed": "2016-02-05T15:38:10.779Z", + "items": [ + { + "title": "Tomme de Savoie AOC", + "sku": 1000029, + "price": 5.6, + "finalprice": 5.6, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "evalet olivier", + "note": "code 1956", + "streetAdress": "34 route chêne", + "floor": "2", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-05T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1997473, + "lng": 6.1692497 + } + }, + "sum": 5.6, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000624, + "email": "elidesign@infomaniak.ch", + "payment": { + "alias": "45078aa35123c6977224430a5ff762631eb8a9673d98c39c3f7f885b04a6a132c37ccca8e1fd3dde564337be6341abbb3b876f333c9d9e3acb7e83cfa5010cda1caae01dd2cbb610569d3055c8b8c4bc0e0e0e0e", + "number": "xxxx-xxxx-xxxx-1337", + "issuer": "mastercard", + "expiry": "9/2018", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 152.15 the Sat Jan 17 1970 21:04:58 GMT+0100 (CET)", + "capture 152.15 the Sat Jan 17 1970 21:04:58 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "d04bc7b431f429ed3dbd83687acdfd8305cc90179a9f4296031dfc89e55006260e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-05T18:57:26.281Z", + "closed": "2016-02-09T16:56:08.788Z", + "items": [ + { + "title": "Gruyère vieux (26 mois d'affinage)", + "sku": 1000025, + "price": 7.35, + "finalprice": 7.35, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "ascari varady elisabeth", + "note": "--- La livraison : Mme ASCARI GRAZIELLA le code d'entrée après 17h00 - 7356", + "streetAdress": "20 a avenue du bouchet", + "floor": "3", + "postalCode": "1209", + "region": "Genève", + "when": "2016-02-09T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2185013, + "lng": 6.122540799999999 + }, + "bags": 2 + }, + "sum": 7.35, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000625, + "email": "annecanepa@gmail.com", + "payment": { + "alias": "e4579fa6dd094f952d055b39f0573a4f89926e8ae304e1cc3dabe47cf4ade8b9c31fa3e164059412a9d321725d8098faf853e1a960078f2e3f401d7b67c3bccfcf51071f8430ec0bb5987e50b444e26d0e0e0e0e", + "number": "xxxx-xxxx-xxxx-0119", + "issuer": "visa", + "expiry": "6/2016", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 135.25 the Sat Jan 17 1970 21:06:01 GMT+0100 (CET)", + "capture 135.25 the Sat Jan 17 1970 21:06:01 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "be00da0429fb364b718595503e34aa0c3a02d177269ebb23fdecaedf63b0d2b10e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-06T12:16:42.579Z", + "closed": "2016-02-09T16:56:10.888Z", + "items": [ + { + "title": "Petit camembert", + "sku": 1000027, + "price": 6.5, + "finalprice": 6.5, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Saint-félicien affiné", + "sku": 1000206, + "price": 7.4, + "finalprice": 7.4, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "canepa anne", + "note": "appartement 52A", + "streetAdress": "118 route de florissant", + "floor": "5", + "postalCode": "1206", + "region": "Genève", + "when": "2016-02-09T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1899536, + "lng": 6.1663951 + }, + "bags": 2 + }, + "sum": 13.9, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000626, + "email": "leo@verhoeven.ch", + "payment": { + "alias": "0ed587ff30df4cd26fc021f49837aa559bd6c45c05f02415a5d28894d28638efb657a34ce2a0e0b9ea3c054a1b35f6c4150416e59eac0323bddb46e1843da23025f8e62b2f7275cb4516cf601d0e98f80e0e0e0e", + "number": "xxxx-xxxx-xxxx-0920", + "issuer": "mastercard", + "expiry": "8/2018", + "fees": { + "shipping": 0 + }, + "logs": [ + "authorized amount 82.35 the Sat Jan 17 1970 21:07:44 GMT+0100 (CET)", + "capture 82.35 the Sat Jan 17 1970 21:07:44 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "2f34a634d04a4e0e2bf25b28f309dbdfa3595e22ec51aa9b163511eb54091a710e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-07T16:58:16.197Z", + "closed": "2016-02-09T16:56:13.382Z", + "items": [ + { + "title": "Brie à la farce truffée", + "sku": 1000402, + "price": 11.8, + "finalprice": 11.8, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Vacherin de Fribourg", + "sku": 1000408, + "price": 5.6, + "finalprice": 24.8, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 4, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Plaisir au Chablis", + "sku": 1000488, + "price": 10, + "finalprice": 7.4, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "verhoeven simon", + "note": "c/o Delphine et Olivier Avalet Cluzel", + "streetAdress": "34 route de chene", + "floor": "2", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-09T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1997473, + "lng": 6.1692497 + } + }, + "sum": 44, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000628, + "email": "fm@fabiennemuller.ch", + "payment": { + "alias": "713dbef234f6be147f691ee4a58a5a52b2a2c8212999d2ff470dc17dbc1f201d3d817807fd037f87eba40919ec4dbef8b47089608bc47ffcb5c5be498019a2a372f710ad0976ec9a8b264c4265d9b8610e0e0e0e", + "number": "xxxx-xxxx-xxxx-4646", + "issuer": "mastercard", + "expiry": "1/2018", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 50.95 the Sat Jan 17 1970 21:07:56 GMT+0100 (CET)", + "capture 50.95 the Sat Jan 17 1970 21:07:56 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "19bb5f7dcb1e4f121a38213fa023e045b5fff73bdf95712c2b0034b5724684650e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-07T20:15:36.373Z", + "closed": "2016-02-09T16:56:17.937Z", + "items": [ + { + "title": "Beurre en motte", + "sku": 1000018, + "price": 5, + "finalprice": 5, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Gruyère vieux (26 mois d'affinage)", + "sku": 1000025, + "price": 7.35, + "finalprice": 7.1, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Bleu de Fribourg", + "sku": 1000403, + "price": 6.6, + "finalprice": 6.6, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "muller fabienne", + "note": "code 3315", + "streetAdress": "rue des noirettes 13", + "floor": "4ème", + "postalCode": "1227", + "region": "Carouge,GE", + "when": "2016-02-09T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1892084, + "lng": 6.135789099999999 + }, + "bags": 1 + }, + "sum": 18.7, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000632, + "email": "delphine.cluzel@gmail.com", + "payment": { + "alias": "735356d2d3fac82c23da5e153ac79ce0df60c378b558c3986cd5741892fee1115e4321c83c364e03039063c68bdb13aec2d2f011005a6142e15307d0e45468a1f7291d6c5134b6d44592618040b5e0030e0e0e0e", + "number": "xxxx-xxxx-xxxx-6190", + "issuer": "visa", + "expiry": "1/2019", + "fees": { + "shipping": 0 + }, + "logs": [ + "authorized amount 67 the Sat Jan 17 1970 21:07:58 GMT+0100 (CET)", + "capture 67 the Sat Jan 17 1970 21:07:58 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "2ae58bef917217ca3ead9354aabaa560f289056e9e5b47c8421f715a6d5be57a0e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-07T21:01:18.559Z", + "closed": "2016-02-09T16:56:27.375Z", + "items": [ + { + "title": "Tomme fleurette", + "sku": 1000404, + "price": 5.1, + "finalprice": 5.1, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "cluzel evalet delphine", + "note": "code d'entrée : 1956", + "streetAdress": "route de chêne 34", + "floor": "2", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-09T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1997473, + "lng": 6.1692497 + } + }, + "sum": 5.1, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000634, + "email": "fauziah_yusoff@yahoo.fr", + "payment": { + "alias": "468e332b3065962edc22d8dc299ba127411ac0905bf5f13e22ad7efa9c64157d0a649fb5501de2ad388264c5064ceccff033c18a0c8bb26994af56ce0b9b63541969728f4eeaa26fdf2168e2318a0c120e0e0e0e", + "number": "xxxx-xxxx-xxxx-1406", + "issuer": "visa", + "expiry": "12/2017", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 145.2 the Sat Jan 17 1970 21:09:09 GMT+0100 (CET)", + "capture 145.2 the Sat Jan 17 1970 21:09:09 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "479cfba8b9c661056cfb3b447577dc634fff8f9902dfdcdb58b5d335125b91c60e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-08T16:40:41.316Z", + "closed": "2016-02-12T16:20:38.297Z", + "items": [ + { + "title": "Gruyère fruité (16 mois d'affinage)", + "sku": 1000024, + "price": 7.35, + "finalprice": 13.1, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 2, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "gardaz fauziah", + "note": "Il faut passer la porte vitrée et aller au bout de la coursive extérieure, à la dernière porte.", + "streetAdress": "rue des délices 33", + "floor": "5 ème", + "postalCode": "1203", + "region": "Genève", + "when": "2016-02-12T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2081242, + "lng": 6.1346232 + } + }, + "sum": 13.1, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000635, + "email": "michele.terrier@hotmail.ch", + "payment": { + "alias": "bb3ddae9484bf3071571640bb378858f25383fdcc407871b3f5a432de1e5f482d1259cf65c4c34aea26de5d915a6f13912a015d252868622818103f53ae4cad859f08fcc411d05a2c5279c807114458d0e0e0e0e", + "number": "xxxx-xxxx-xxxx-4279", + "issuer": "mastercard", + "expiry": "5/2016", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 173.45 the Sat Jan 17 1970 21:10:03 GMT+0100 (CET)", + "capture 173.45 the Sat Jan 17 1970 21:10:03 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "e282356bb0ab3728a283dde2159ee6eea99aeccabb729dff70d7d59dbdccd8100e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-09T07:30:46.661Z", + "closed": "2016-02-12T16:20:41.486Z", + "items": [ + { + "title": "Lasagne", + "sku": 1000308, + "price": 11, + "finalprice": 11, + "vendor": "purogusto", + "part": "250gr", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + }, + "variant": { + "title": "Lasagne épinards-ricotta" + } + }, + { + "title": "Lasagne", + "sku": 1000308, + "price": 11, + "finalprice": 11, + "vendor": "purogusto", + "part": "250gr", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + }, + "variant": { + "title": "Lasagne tomates-mozzarella" + } + }, + { + "title": "Gâteau à l’orange", + "sku": 1000309, + "price": 4, + "finalprice": 4, + "vendor": "purogusto", + "part": "1pce", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Parmigiana d’aubergines", + "sku": 1000310, + "price": 11, + "finalprice": 11, + "vendor": "purogusto", + "part": "250gr", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pain naturellement sans gluten", + "sku": 1000313, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "~900gr", + "quantity": 1, + "category": "Boulangerie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Muffin salé (naturellement sans gluten)", + "sku": 1000314, + "price": 5, + "finalprice": 5, + "vendor": "purogusto", + "part": "1pce", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + }, + "variant": { + "title": "Courgettes, pesto" + } + }, + { + "title": "Quiche salée", + "sku": 1000316, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "1 pce", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "pharmacie des bergues", + "note": "Livrer directement à la pharmacie svp", + "streetAdress": "25 quai des bergues", + "floor": "Arcade", + "postalCode": "1201", + "region": "Genève", + "when": "2016-02-12T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2064842, + "lng": 6.145340099999999 + } + }, + "sum": 54, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000638, + "email": "elidesign@infomaniak.ch", + "payment": { + "alias": "45078aa35123c6977224430a5ff762631eb8a9673d98c39c3f7f885b04a6a132c37ccca8e1fd3dde564337be6341abbb3b876f333c9d9e3acb7e83cfa5010cda1caae01dd2cbb610569d3055c8b8c4bc0e0e0e0e", + "number": "xxxx-xxxx-xxxx-1337", + "issuer": "mastercard", + "expiry": "9/2018", + "fees": { + "shipping": 5 + }, + "logs": [ + "authorized amount 227.75 the Sat Jan 17 1970 21:10:31 GMT+0100 (CET)", + "capture 227.75 the Sat Jan 17 1970 21:10:31 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "c554f7e08d4ef31aa1dd3fe5b75e6aa28b3467f7a2292f2f4303bb76f9d83cc90e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-09T15:22:34.703Z", + "closed": "2016-02-12T16:20:44.186Z", + "items": [ + { + "title": "Beurre en motte", + "sku": 1000018, + "price": 5, + "finalprice": 5, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Gruyère vieux (26 mois d'affinage)", + "sku": 1000025, + "price": 7.35, + "finalprice": 7.35, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Chèvre frais", + "sku": 1000205, + "price": 4.9, + "finalprice": 4.9, + "vendor": "les-fromages-de-gaetan", + "part": "~150gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Gâteau à l’orange", + "sku": 1000309, + "price": 4, + "finalprice": 4, + "vendor": "purogusto", + "part": "1pce", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Raclette St-Theodule", + "sku": 1000399, + "price": 4.05, + "finalprice": 69.6, + "vendor": "les-fromages-de-gaetan", + "part": "~150gr", + "quantity": 16, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "ascari varady elisabeth", + "note": "--- La livraison : Mme ASCARI GRAZIELLA le code d'entrée après 17h00 - 7356", + "streetAdress": "20 a avenue du bouchet", + "floor": "3", + "postalCode": "1209", + "region": "Genève", + "when": "2016-02-12T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2185013, + "lng": 6.122540799999999 + } + }, + "sum": 90.85, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000645, + "email": "michele.terrier@hotmail.ch", + "payment": { + "alias": "bb3ddae9484bf3071571640bb378858f25383fdcc407871b3f5a432de1e5f482d1259cf65c4c34aea26de5d915a6f13912a015d252868622818103f53ae4cad859f08fcc411d05a2c5279c807114458d0e0e0e0e", + "number": "xxxx-xxxx-xxxx-4279", + "issuer": "mastercard", + "expiry": "5/2016", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 83.4 the Sat Jan 17 1970 21:17:59 GMT+0100 (CET)", + "capture 83.4 the Sat Jan 17 1970 21:17:59 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "50cb32d6f480aa33aa661f9d55dafa9444ece6c1653940404b589b84154f24d00e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-14T19:51:31.048Z", + "closed": "2016-02-16T15:13:52.512Z", + "items": [ + { + "title": "Petit caprèse au chocolat noir", + "sku": 1000306, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "2pce", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Lasagne", + "sku": 1000308, + "price": 11, + "finalprice": 11, + "vendor": "purogusto", + "part": "250gr", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + }, + "variant": { + "title": "Lasagne tomates-mozzarella" + } + }, + { + "title": "Quiche salée", + "sku": 1000316, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "1 pce", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "pharmacie des bergues", + "note": "Livrer directement à la pharmacie svp", + "streetAdress": "25 quai des bergues", + "floor": "Arcade", + "postalCode": "1201", + "region": "Genève", + "when": "2016-02-16T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2064842, + "lng": 6.145340099999999 + }, + "bags": 1 + }, + "sum": 23, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000646, + "email": "evaleto@gmail.com", + "payment": { + "alias": "fabdfe0d9a0b11b93b41af91de3a19f1be80a97f4c6a871a918c91f40d920876cf26fbd9524f3cb1650f04dd8e14151c925459d45c47051723cbf4ba0939926fae771ba981622fd1b4db2994020ed4540e0e0e0e", + "number": "xxxx-xxxx-xxxx-0347", + "issuer": "visa", + "expiry": "8/2016", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 155.5 the Sat Jan 17 1970 21:18:01 GMT+0100 (CET)", + "capture 155.5 the Sat Jan 17 1970 21:18:01 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "8a06d764d7b6365df59908fd6cbbd9d1c2f0b587628809e303906d8a6921aa270e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-14T20:24:08.726Z", + "closed": "2016-02-16T15:13:54.166Z", + "items": [ + { + "title": "Tiramisu", + "sku": 1000307, + "price": 10, + "finalprice": 10, + "vendor": "purogusto", + "part": "~160gr", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "evalet olivier", + "note": "code 1956", + "streetAdress": "34 route chêne", + "floor": "2", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-16T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1997473, + "lng": 6.1692497 + }, + "bags": 2 + }, + "sum": 10, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000649, + "email": "atank@infomaniak.ch", + "payment": { + "alias": "6f873b28c126d508e9f5402fa96b7446106bbfd31ce6c72a1050edab602bbea70a2858adde50b3cc5a4f580bc44d81426baab0dbe40cb611b4435dc6c58e0af976c97934fe487ba4ac2c3470ffa10a780e0e0e0e", + "number": "xxxx-xxxx-xxxx-8674", + "issuer": "mastercard", + "expiry": "4/2016", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 64 the Sat Jan 17 1970 21:20:13 GMT+0100 (CET)", + "capture 64 the Sat Jan 17 1970 21:20:13 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "5c2479a8c733bb5df4114a37eb20557f8522ef2f3e3e98138414f281b1d357320e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-16T09:03:28.852Z", + "closed": "2016-02-19T15:19:51.923Z", + "items": [ + { + "title": "Pain naturellement sans gluten", + "sku": 1000313, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "~900gr", + "quantity": 1, + "category": "Boulangerie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "tank anouk", + "note": "code : 1009", + "streetAdress": "48 rte de malagnou", + "floor": "5e", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-19T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1966198, + "lng": 6.162958199999999 + }, + "bags": 1 + }, + "sum": 6, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000650, + "email": "mahazein@gmail.com", + "payment": { + "alias": "22c9551789fd6b209d9ca3fd05084b07d403386773c5a6dc1bd097192be0f0a736caf1575b6e0324f2ee3881a30983621d8f00599a2244a9d133a26d629a8125082dc3aa1191e52a872052d54d08344b0e0e0e0e", + "number": "xxxx-xxxx-xxxx-7826", + "issuer": "mastercard", + "expiry": "11/2018", + "fees": { + "shipping": 0 + }, + "logs": [ + "authorized amount 107.75 the Sat Jan 17 1970 21:20:23 GMT+0100 (CET)", + "capture 107.75 the Sat Jan 17 1970 21:20:23 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "1acad1c0d04cd87eebc93cc836cf67a54ad0547bdedbad595c21d8cfa3b07cb30e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-16T11:59:27.186Z", + "closed": "2016-02-19T15:19:57.791Z", + "items": [ + { + "title": "Mini chevrot", + "sku": 1000020, + "price": 4.9, + "finalprice": 9.8, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 2, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Gruyère fruité (16 mois d'affinage)", + "sku": 1000024, + "price": 7.35, + "finalprice": 7.8, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Ossau-iraty", + "sku": 1000028, + "price": 6.6, + "finalprice": 6.6, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pain naturellement sans gluten", + "sku": 1000313, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "~900gr", + "quantity": 1, + "category": "Boulangerie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "zein maha", + "streetAdress": "bergalonne 12", + "floor": "1", + "postalCode": "1205", + "region": "Genève", + "when": "2016-02-19T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1980284, + "lng": 6.1376249 + } + }, + "sum": 30.200000000000003, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000651, + "email": "elidesign@infomaniak.ch", + "payment": { + "alias": "45078aa35123c6977224430a5ff762631eb8a9673d98c39c3f7f885b04a6a132c37ccca8e1fd3dde564337be6341abbb3b876f333c9d9e3acb7e83cfa5010cda1caae01dd2cbb610569d3055c8b8c4bc0e0e0e0e", + "number": "xxxx-xxxx-xxxx-1337", + "issuer": "mastercard", + "expiry": "9/2018", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 62.45 the Sat Jan 17 1970 21:20:34 GMT+0100 (CET)", + "capture 62.45 the Sat Jan 17 1970 21:20:34 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "e1a297e3f19adbbf12266fb209b4d0049d4eb936f3057624fffc523ea7b7ee520e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-16T14:52:25.315Z", + "closed": "2016-02-19T15:20:01.048Z", + "items": [ + { + "title": "Beurre en motte", + "sku": 1000018, + "price": 5, + "finalprice": 5, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Gâteau à l’orange", + "sku": 1000309, + "price": 4, + "finalprice": 4, + "vendor": "purogusto", + "part": "1pce", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "ascari varady elisabeth", + "note": "--- La livraison : Mme ASCARI GRAZIELLA le code d'entrée après 17h00 - 7356", + "streetAdress": "20 a avenue du bouchet", + "floor": "3", + "postalCode": "1209", + "region": "Genève", + "when": "2016-02-19T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2185013, + "lng": 6.122540799999999 + }, + "bags": 1 + }, + "sum": 9, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000652, + "email": "peczelyl@hotmail.com", + "payment": { + "alias": "880f1c5a118400b2a9b74f5e6817e66444a63f23510fad888cb8a00866ea007912b7a2f824681afa057fd4a3f837e74a798aa7df83bc4300a745c5f35e99b52825f7a6055e75bcaa81fb06ac406f88940e0e0e0e", + "number": "xxxx-xxxx-xxxx-0887", + "issuer": "mastercard", + "expiry": "11/2017", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 132.55 the Sat Jan 17 1970 21:21:40 GMT+0100 (CET)", + "capture 132.55 the Sat Jan 17 1970 21:21:40 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "30b0c32ed9cd367c852450280f3efe0f56c7a4d6a415cee9ef7c80f1cb335ca90e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-17T09:08:57.631Z", + "closed": "2016-02-19T15:20:03.239Z", + "items": [ + { + "title": "Vacherin de Fribourg", + "sku": 1000408, + "price": 5.6, + "finalprice": 6.3, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "peczely lilla sara", + "note": "Doorcode 2692E; 5th floor; please leave it in front of the door. Code de la porte 2692 de E; 5ème étage; laissez s'il vous plaît en face de la porte", + "streetAdress": "24 rue jacques grosselin", + "floor": "5 (2692E)", + "postalCode": "1227", + "region": "Carouge,GE", + "when": "2016-02-19T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.185955, + "lng": 6.13531 + }, + "bags": 1 + }, + "sum": 6.3, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000653, + "email": "frederique.bouchet@gmail.com", + "payment": { + "alias": "a26d947073c6d8e4d19013ab4c5b8a833e36f537705667fb7f9d393eae0693f0e389bd131148d94bafafe7951b983af612b67d637a9ed1cbff06e11dd3f90da40fa9b23ffe427227e0120a442f25d5080e0e0e0e", + "number": "xxxx-xxxx-xxxx-8691", + "issuer": "visa", + "expiry": "5/2016", + "fees": { + "shipping": 7.5 + }, + "logs": [ + "authorized amount 179.95 the Sat Jan 17 1970 21:21:41 GMT+0100 (CET)", + "capture 179.95 the Sat Jan 17 1970 21:21:41 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "8f76b8c1d24abb3ff54676e037e1952e354197c8e6c7958e531a9e49efe172fa0e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-17T09:31:58.698Z", + "closed": "2016-02-19T15:20:05.870Z", + "items": [ + { + "title": "Beurre en motte", + "sku": 1000018, + "price": 5, + "finalprice": 5, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Morbier", + "sku": 1000026, + "price": 5.4, + "finalprice": 5.4, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Ossau-iraty", + "sku": 1000028, + "price": 6.6, + "finalprice": 7.7, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "bouchet frédérique", + "note": "jusqu'à 17h30, livraison à Ushitomi. Dès 17h30, livraison à la maison. Merci!", + "streetAdress": "rue ferrier 10", + "floor": "4ème étage", + "postalCode": "1202", + "region": "Genève", + "when": "2016-02-19T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2157484, + "lng": 6.146484399999999 + }, + "bags": 2 + }, + "sum": 18.1, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000655, + "email": "delphine.cluzel@gmail.com", + "payment": { + "alias": "735356d2d3fac82c23da5e153ac79ce0df60c378b558c3986cd5741892fee1115e4321c83c364e03039063c68bdb13aec2d2f011005a6142e15307d0e45468a1f7291d6c5134b6d44592618040b5e0030e0e0e0e", + "number": "xxxx-xxxx-xxxx-6190", + "issuer": "visa", + "expiry": "1/2019", + "fees": { + "shipping": 0 + }, + "logs": [ + "authorized amount 107.35 the Sat Jan 17 1970 21:22:25 GMT+0100 (CET)", + "capture 107.35 the Sat Jan 17 1970 21:22:25 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "5f0e687f38fd8e1bd961a9a80052ed2f7f2132625c77c41aa6be166b6afa397b0e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-17T21:51:31.513Z", + "closed": "2016-02-19T15:20:19.782Z", + "items": [ + { + "title": "Beurre en motte", + "sku": 1000018, + "price": 5, + "finalprice": 5, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Petit camembert", + "sku": 1000027, + "price": 6.5, + "finalprice": 6.5, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Tomme de Savoie AOC", + "sku": 1000029, + "price": 5.6, + "finalprice": 5.6, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Le Maréchal", + "sku": 1000401, + "price": 8.4, + "finalprice": 8.4, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Tomme fleurette", + "sku": 1000404, + "price": 5.1, + "finalprice": 5.1, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "cluzel evalet delphine", + "note": "code d'entrée : 1956", + "streetAdress": "route de chêne 34", + "floor": "2", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-19T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1997473, + "lng": 6.1692497 + }, + "bags": 1 + }, + "sum": 30.6, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000657, + "email": "delphine.cluzel@gmail.com", + "payment": { + "alias": "735356d2d3fac82c23da5e153ac79ce0df60c378b558c3986cd5741892fee1115e4321c83c364e03039063c68bdb13aec2d2f011005a6142e15307d0e45468a1f7291d6c5134b6d44592618040b5e0030e0e0e0e", + "number": "xxxx-xxxx-xxxx-6190", + "issuer": "visa", + "expiry": "1/2019", + "fees": { + "shipping": 0 + }, + "logs": [ + "authorized amount 151.1 the Sat Jan 17 1970 21:28:08 GMT+0100 (CET)", + "capture 151.1 the Sat Jan 17 1970 21:28:08 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "e528b15229dee5f6c303873fc8cff7a00acd848d9b053ca8fc902a4ac55064590e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-21T21:09:16.637Z", + "closed": "2016-02-23T19:26:00.610Z", + "items": [ + { + "title": "Laious de brebis", + "sku": 1000022, + "price": 10, + "finalprice": 10, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Le Maréchal", + "sku": 1000401, + "price": 8.4, + "finalprice": 11.4, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pizza Margherita de farine mi-blanche", + "sku": 1000522, + "price": 10, + "finalprice": 10, + "vendor": "purogusto", + "part": "~450g", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pizza de farine mi-blanche aux légumes grillés", + "sku": 1000523, + "price": 12, + "finalprice": 12, + "vendor": "purogusto", + "part": "~550g", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "cluzel evalet delphine", + "note": "code d'entrée : 1956", + "streetAdress": "route de chêne 34", + "floor": "2", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-23T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1997473, + "lng": 6.1692497 + }, + "bags": 1 + }, + "sum": 43.4, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000658, + "email": "jean.terrier@bluewin.ch", + "payment": { + "alias": "77cb50d4d904a15e52f6a5aea1b22760f14904b4f640eb223a44b155a422f9d258a8f19010e184ec75e791f853a737b5b8713b6a97b1dc58160d89685190b5a55ce7f93fd60e36788c339997526a5f5e0e0e0e0e", + "number": "xxxx-xxxx-xxxx-9568", + "issuer": "mastercard", + "expiry": "5/2016", + "fees": { + "shipping": 7.5 + }, + "logs": [ + "authorized amount 181.6 the Sat Jan 17 1970 21:28:10 GMT+0100 (CET)", + "capture 181.6 the Sat Jan 17 1970 21:28:10 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "f06ed77e0784886e2c5589214644e7a7d21d168f108b3e4481cc027799e277ca0e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-21T21:30:46.323Z", + "closed": "2016-02-23T19:26:03.664Z", + "items": [ + { + "title": "Mini chevrot", + "sku": 1000020, + "price": 4.9, + "finalprice": 9.8, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 2, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "terrier jean", + "note": "Code d'entrée: 1942", + "streetAdress": "1 rue marignac", + "floor": "5", + "postalCode": "1206", + "region": "Genève", + "when": "2016-02-23T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1944086, + "lng": 6.153050599999999 + }, + "bags": 2 + }, + "sum": 9.8, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000659, + "email": "jessica.loiseau@bluewin.ch", + "payment": { + "alias": "0b9573485de95271dc061cfb4383fc5396022dc39ad214b47a6b06090f6f410beadf667c1556f8e57623d4d47e11379b3d6f22159f41c2b668ad51e80e5c9b533876f68417546946a2f8072d5a1e5be50e0e0e0e", + "number": "xxxx-xxxx-xxxx-6833", + "issuer": "visa", + "expiry": "10/2017", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 74.65 the Sat Jan 17 1970 21:29:14 GMT+0100 (CET)", + "capture 74.65 the Sat Jan 17 1970 21:29:14 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "b30631d097e334e52267a33807fe11fef4870f99482d10bac3e117bd6e8bc1420e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-22T15:20:24.037Z", + "closed": "2016-02-26T16:40:18.694Z", + "items": [ + { + "title": "Gruyère fruité (16 mois d'affinage)", + "sku": 1000024, + "price": 7.35, + "finalprice": 7.35, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Tiramisu", + "sku": 1000307, + "price": 10, + "finalprice": 10, + "vendor": "purogusto", + "part": "~160gr", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Muffin salé (naturellement sans gluten)", + "sku": 1000314, + "price": 5, + "finalprice": 5, + "vendor": "purogusto", + "part": "1pce", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + }, + "variant": { + "title": "Olives noires, feta, tomates cerises" + } + }, + { + "title": "Muffin salé (naturellement sans gluten)", + "sku": 1000314, + "price": 5, + "finalprice": 5, + "vendor": "purogusto", + "part": "1pce", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + }, + "variant": { + "title": "Courgettes, pesto" + } + } + ], + "shipping": { + "name": "loiseau jessica", + "note": "Code entrée:9621", + "streetAdress": "16, avenue peschier", + "floor": "5", + "postalCode": "1206", + "region": "Genève", + "when": "2016-02-26T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1919862, + "lng": 6.156799899999999 + } + }, + "sum": 27.35, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000660, + "email": "elidesign@infomaniak.ch", + "payment": { + "alias": "45078aa35123c6977224430a5ff762631eb8a9673d98c39c3f7f885b04a6a132c37ccca8e1fd3dde564337be6341abbb3b876f333c9d9e3acb7e83cfa5010cda1caae01dd2cbb610569d3055c8b8c4bc0e0e0e0e", + "number": "xxxx-xxxx-xxxx-1337", + "issuer": "mastercard", + "expiry": "9/2018", + "fees": { + "shipping": 7 + }, + "logs": [ + "authorized amount 90.1 the Sat Jan 17 1970 21:30:59 GMT+0100 (CET)", + "capture 90.1 the Sat Jan 17 1970 21:30:59 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "53d51f18230d868016531b3e3d55238b54846ea7969fe11c3b8c1ec49a683b3a0e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-23T20:38:43.790Z", + "closed": "2016-02-26T16:40:20.242Z", + "items": [ + { + "title": "Tomme de Savoie AOC", + "sku": 1000029, + "price": 5.6, + "finalprice": 5.9, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "ascari varady elisabeth", + "note": "--- La livraison : Mme ASCARI GRAZIELLA le code d'entrée après 17h00 - 7356", + "streetAdress": "20 a avenue du bouchet", + "floor": "3", + "postalCode": "1209", + "region": "Genève", + "when": "2016-02-26T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2185013, + "lng": 6.122540799999999 + } + }, + "sum": 5.9, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000661, + "email": "francois@monpetitcoin.com", + "payment": { + "alias": "0f31191c99fea2fc5d748193844c53fe569dfc9f7fe2233f28053be20621ab1faae1ef29cb75ce4054064c4ab9b5ff17210d5a84143942559d0db86a57e553a52f071c7c31641114ad4e5369e0b696bf0e0e0e0e", + "number": "xxxx-xxxx-xxxx-2594", + "issuer": "mastercard", + "expiry": "11/2018", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 71.55 the Sat Jan 17 1970 21:31:00 GMT+0100 (CET)", + "capture 71.55 the Sat Jan 17 1970 21:31:00 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "ff7207543d09e157fa6ce7787b4271082c78becd22a1498d487d07f2c56c85eb0e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-23T20:54:42.640Z", + "closed": "2016-02-26T16:40:21.737Z", + "items": [ + { + "title": "Pizza de farine mi-blanche aux légumes grillés", + "sku": 1000523, + "price": 12, + "finalprice": 12, + "vendor": "purogusto", + "part": "~550g", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "suter françois", + "note": "c/o Cobweb (je fais livrer au bureau, j'espère que vous passez pendant les heures de travail)", + "streetAdress": "route des jeunes 5c", + "floor": "4", + "postalCode": "1227", + "region": "Carouge,GE", + "when": "2016-02-26T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1917601, + "lng": 6.1285121 + } + }, + "sum": 12, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000662, + "email": "michele.terrier@hotmail.ch", + "payment": { + "alias": "bb3ddae9484bf3071571640bb378858f25383fdcc407871b3f5a432de1e5f482d1259cf65c4c34aea26de5d915a6f13912a015d252868622818103f53ae4cad859f08fcc411d05a2c5279c807114458d0e0e0e0e", + "number": "xxxx-xxxx-xxxx-4279", + "issuer": "mastercard", + "expiry": "5/2016", + "fees": { + "shipping": 5 + }, + "logs": [ + "authorized amount 233.25 the Sat Jan 17 1970 21:31:02 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "96d97472e419f8b30413d68896d44ea38829d751520d233008af3d0dbcdd72280e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-23T21:20:48.637Z", + "closed": "2016-04-01T21:20:48.637Z", + "items": [ + { + "title": "Viande séchée de Genève", + "sku": 1000030, + "price": 8.6, + "finalprice": 8.6, + "vendor": "les-fromages-de-gaetan", + "part": "~100gr", + "quantity": 1, + "category": "Boucherie et charcuterie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Petit caprèse au chocolat noir", + "sku": 1000306, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "2pce", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Lasagne", + "sku": 1000308, + "price": 11, + "finalprice": 11, + "vendor": "purogusto", + "part": "250gr", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + }, + "variant": { + "title": "Lasagne tomates-mozzarella" + } + }, + { + "title": "Lasagne", + "sku": 1000308, + "price": 11, + "finalprice": 11, + "vendor": "purogusto", + "part": "250gr", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + }, + "variant": { + "title": "**Nouveauté** Lasagne courgettes-pesto" + } + }, + { + "title": "Gâteau à l’orange", + "sku": 1000309, + "price": 4, + "finalprice": 4, + "vendor": "purogusto", + "part": "1pce", + "quantity": 1, + "category": "Douceurs & chocolats", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Parmigiana d’aubergines", + "sku": 1000310, + "price": 11, + "finalprice": 11, + "vendor": "purogusto", + "part": "250gr", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pain naturellement sans gluten", + "sku": 1000313, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "~900gr", + "quantity": 1, + "category": "Boulangerie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Muffin salé (naturellement sans gluten)", + "sku": 1000314, + "price": 5, + "finalprice": 5, + "vendor": "purogusto", + "part": "1pce", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + }, + "variant": { + "title": "Olives noires, feta, tomates cerises" + } + }, + { + "title": "Muffin salé (naturellement sans gluten)", + "sku": 1000314, + "price": 5, + "finalprice": 5, + "vendor": "purogusto", + "part": "1pce", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + }, + "variant": { + "title": "Courgettes, pesto" + } + } + ], + "shipping": { + "name": "pharmacie des bergues", + "note": "Livrer directement à la pharmacie svp", + "streetAdress": "25 quai des bergues", + "floor": "Arcade", + "postalCode": "1201", + "region": "Genève", + "when": "2016-02-26T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2064842, + "lng": 6.145340099999999 + } + }, + "sum": 67.6, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000664, + "email": "christine.heilmann@frantour.ch", + "payment": { + "alias": "60562d3543946d58a829466ec40f7261afd0ba39a4e146bae2d31715ec17370c5bf4dd2745afedc86b580243e6ad9db955f3836a26568004c3f3f0bd62e0e941b4d5b36f6602c6a0d9729d24531c94c80e0e0e0e", + "number": "xxxx-xxxx-xxxx-3265", + "issuer": "visa", + "expiry": "6/2017", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 148.55 the Sat Jan 17 1970 21:31:09 GMT+0100 (CET)", + "capture 148.55 the Sat Jan 17 1970 21:31:09 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "affbb816ddfde1c0dc7e1d9a8dcff079a6b174b235ce029a3da324782e8b18d50e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-23T23:18:26.892Z", + "closed": "2016-02-26T16:40:28.641Z", + "items": [ + { + "title": "Viande séchée de Genève", + "sku": 1000030, + "price": 8.6, + "finalprice": 17.4, + "vendor": "les-fromages-de-gaetan", + "part": "~100gr", + "quantity": 1, + "category": "Boucherie et charcuterie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pâtes de blé BIO avec sauce tomate", + "sku": 1000519, + "price": 13, + "finalprice": 13, + "vendor": "purogusto", + "part": "750g", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pizza de farine mi-blanche aux légumes grillés", + "sku": 1000523, + "price": 12, + "finalprice": 12, + "vendor": "purogusto", + "part": "~550g", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "heilmann christine", + "note": "Interphone", + "streetAdress": "16 chemin des tulipiers", + "floor": "4", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-26T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2011968, + "lng": 6.173349099999999 + } + }, + "sum": 42.4, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000665, + "email": "atank@infomaniak.ch", + "payment": { + "alias": "6f873b28c126d508e9f5402fa96b7446106bbfd31ce6c72a1050edab602bbea70a2858adde50b3cc5a4f580bc44d81426baab0dbe40cb611b4435dc6c58e0af976c97934fe487ba4ac2c3470ffa10a780e0e0e0e", + "number": "xxxx-xxxx-xxxx-8674", + "issuer": "mastercard", + "expiry": "4/2016", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 60.6 the Sat Jan 17 1970 21:31:46 GMT+0100 (CET)", + "capture 60.6 the Sat Jan 17 1970 21:31:46 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "a90267ddaa9e74ea12d6a3b92d49621085744c4a7c37b3fee19f693a5504c8c10e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-24T09:40:42.811Z", + "closed": "2016-02-26T16:40:30.154Z", + "items": [ + { + "title": "Pain naturellement sans gluten", + "sku": 1000313, + "price": 6, + "finalprice": 6, + "vendor": "purogusto", + "part": "~900gr", + "quantity": 1, + "category": "Boulangerie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "tank anouk", + "note": "code : 1009", + "streetAdress": "48 rte de malagnou", + "floor": "5e", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-26T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1966198, + "lng": 6.162958199999999 + } + }, + "sum": 6, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000666, + "email": "elidesign@infomaniak.ch", + "payment": { + "alias": "45078aa35123c6977224430a5ff762631eb8a9673d98c39c3f7f885b04a6a132c37ccca8e1fd3dde564337be6341abbb3b876f333c9d9e3acb7e83cfa5010cda1caae01dd2cbb610569d3055c8b8c4bc0e0e0e0e", + "number": "xxxx-xxxx-xxxx-1337", + "issuer": "mastercard", + "expiry": "9/2018", + "fees": { + "shipping": 7.5 + }, + "logs": [ + "authorized amount 181.8 the Sat Jan 17 1970 21:31:56 GMT+0100 (CET)", + "capture 181.8 the Sat Jan 17 1970 21:31:56 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "f2dd8438554b98e89ec1fb759c1d6fed3e98fee667a5ad0bc631969c5cd2616b0e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-24T12:23:04.693Z", + "closed": "2016-02-26T16:40:42.181Z", + "items": [ + { + "title": "Ossau-iraty", + "sku": 1000028, + "price": 6.6, + "finalprice": 6.6, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Chèvre frais", + "sku": 1000205, + "price": 4.9, + "finalprice": 4.9, + "vendor": "les-fromages-de-gaetan", + "part": "~150gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Saint-félicien affiné", + "sku": 1000206, + "price": 7.4, + "finalprice": 7.4, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Parmigiana d’aubergines", + "sku": 1000310, + "price": 11, + "finalprice": 11, + "vendor": "purogusto", + "part": "250gr", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "ascari varady elisabeth", + "note": "--- La livraison : Mme ASCARI GRAZIELLA le code d'entrée après 17h00 - 7356", + "streetAdress": "20 a avenue du bouchet", + "floor": "3", + "postalCode": "1209", + "region": "Genève", + "when": "2016-02-26T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.2185013, + "lng": 6.122540799999999 + } + }, + "sum": 29.9, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000667, + "email": "carinefluckiger@hotmail.com", + "payment": { + "alias": "a27ffaae01cf520e898d0874489d2cbaa93a9b0ce65ed334d38cc12fec2b75190e0e0e0e", + "number": null, + "issuer": "invoice", + "expiry": "12/2016", + "fees": { + "shipping": 0 + }, + "logs": [ + "authorized amount 167 the Wed Feb 24 2016 18:04:34 GMT+0100 (CET)", + "invoice 131.8 the Fri Feb 26 2016 17:40:42 GMT+0100 (CET)", + "captured 131.8 the Mon Mar 07 2016 15:41:50 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "c5165adb44cd1fa443c6ad3c0a64312f0e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-24T17:04:33.873Z", + "closed": "2016-03-07T14:41:50.720Z", + "items": [ + { + "title": "Laious de brebis", + "sku": 1000022, + "price": 10, + "finalprice": 10, + "vendor": "les-fromages-de-gaetan", + "part": "~300gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Petit camembert", + "sku": 1000027, + "price": 6.5, + "finalprice": 6.5, + "vendor": "les-fromages-de-gaetan", + "part": "1pce", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pâtes d'épeautre BIO avec sauce noix", + "sku": 1000521, + "price": 18, + "finalprice": 18, + "vendor": "purogusto", + "part": "750g", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "fluckiger carine", + "note": "Code d'immeuble: 0589#", + "streetAdress": "quai du cheval-blanc 18", + "floor": "rez", + "postalCode": "1227", + "region": "Genève", + "when": "2016-02-26T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1916334, + "lng": 6.1393324 + } + }, + "sum": 34.5, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000668, + "email": "mahazein@gmail.com", + "payment": { + "alias": "22c9551789fd6b209d9ca3fd05084b07d403386773c5a6dc1bd097192be0f0a736caf1575b6e0324f2ee3881a30983621d8f00599a2244a9d133a26d629a8125082dc3aa1191e52a872052d54d08344b0e0e0e0e", + "number": "xxxx-xxxx-xxxx-7826", + "issuer": "mastercard", + "expiry": "11/2018", + "fees": { + "shipping": 0 + }, + "logs": [ + "authorized amount 88.05 the Sat Jan 17 1970 21:32:16 GMT+0100 (CET)", + "capture 88.05 the Sat Jan 17 1970 21:32:16 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "a32dd7739194db9241095c775d2856f59af3338778199aa553395062470b67800e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-24T18:00:43.585Z", + "closed": "2016-02-26T16:40:45.119Z", + "items": [ + { + "title": "Pâtes d'épeautre BIO avec sauce noix", + "sku": 1000521, + "price": 18, + "finalprice": 18, + "vendor": "purogusto", + "part": "750g", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Pizza de farine mi-blanche aux légumes grillés", + "sku": 1000523, + "price": 12, + "finalprice": 12, + "vendor": "purogusto", + "part": "~550g", + "quantity": 1, + "category": "Traiteur", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "zein maha", + "streetAdress": "bergalonne 12", + "floor": "1", + "postalCode": "1205", + "region": "Genève", + "when": "2016-02-26T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1980284, + "lng": 6.1376249 + } + }, + "sum": 30, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +}, +{ + "oid": 2000669, + "email": "delphine.cluzel@gmail.com", + "payment": { + "alias": "735356d2d3fac82c23da5e153ac79ce0df60c378b558c3986cd5741892fee1115e4321c83c364e03039063c68bdb13aec2d2f011005a6142e15307d0e45468a1f7291d6c5134b6d44592618040b5e0030e0e0e0e", + "number": "xxxx-xxxx-xxxx-6190", + "issuer": "visa", + "expiry": "1/2019", + "fees": { + "shipping": 10 + }, + "logs": [ + "authorized amount 172.85 the Sat Jan 17 1970 21:32:26 GMT+0100 (CET)", + "capture 172.85 the Sat Jan 17 1970 21:32:26 GMT+0100 (CET)" + ], + "provider": "stripe", + "handle": "secret", + "status": "paid", + "transaction": "b892553d921b294566fd06d6e041c18420f0f56a199188a0ab007ed7b2acaa850e0e0e0e" + }, + "fulfillments": { + "status": "fulfilled" + }, + "created": "2016-02-24T20:38:07.233Z", + "closed": "2016-02-26T16:40:47.322Z", + "items": [ + { + "title": "Beurre en motte", + "sku": 1000018, + "price": 5, + "finalprice": 5, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Tomme de Savoie AOC", + "sku": 1000029, + "price": 5.6, + "finalprice": 5.6, + "vendor": "les-fromages-de-gaetan", + "part": "~200gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Viande séchée de Genève", + "sku": 1000030, + "price": 8.6, + "finalprice": 8.6, + "vendor": "les-fromages-de-gaetan", + "part": "~100gr", + "quantity": 1, + "category": "Boucherie et charcuterie", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + }, + { + "title": "Chèvre frais", + "sku": 1000205, + "price": 4.9, + "finalprice": 4.9, + "vendor": "les-fromages-de-gaetan", + "part": "~150gr", + "quantity": 1, + "category": "Produits laitiers", + "fulfillment": { + "shipping": "grouped", + "status": "fulfilled" + } + } + ], + "shipping": { + "name": "cluzel evalet delphine", + "note": "code d'entrée : 1956", + "streetAdress": "route de chêne 34", + "floor": "2", + "postalCode": "1208", + "region": "Genève", + "when": "2016-02-26T15:00:00.000Z", + "shipped": false, + "geo": { + "lat": 46.1997473, + "lng": 6.1692497 + } + }, + "sum": 24.1, + "vendors": [ + { + "slug": "les-fromages-de-gaetan", + "name": "les-fromages-de-gaetan", + "fees":0.15, + "address": "todo" + }, + { + "slug": "purogusto", + "fees":0.18, + "name": "purogusto", + "address": "todo" + } + ], + "customer": { + "id": 999 + } +} +]; + +// +// ------------------------ PRODUCTS -------------------------- +// + +exports.Products=[{ + _id : new ObjectId(), + sku:1000001, + title: "Product 2 with cat", + details:{ + description:"description", + comment:"Temps de cuisson : 16 minutes", + gluten:true, + ogm:false, + bio:false, + }, + + attributes:{ + available:true, + comment:false, + discount:true + }, + + pricing: { + stock:10, + price:3.80, + discount:3.0, + part:'100gr' + }, + /* weight:0,1 */ + categories: c.Categories[1]._id, + //un-autre-shop, id:0004, status:true, owner:gluck + vendor:'515ec12e56a8d5961e000006' + },{ + _id : new ObjectId(), + sku:1000002, + title: "Product 2 with cat", + details:{ + description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ", + comment:"Temps de cuisson : 16 minutes", + gluten:true, + ogm:true, + bio:true, + }, + attributes:{ + available:true, + comment:false, + discount:false + }, + variants:[ + {title:'Variation A'} + ], + pricing: { + stock:10, + price:3.80, + part:'0.75L' + }, + /* weight:2 */ + categories: c.Categories[3]._id, + //shop available==true, status!=true + vendor:'515ec12e56a8d5961e000004' + },{ + _id : new ObjectId(), + sku:1000003, + title: "Product 3 with cat", + details:{ + description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ", + comment:"Temps de cuisson : 16 minutes", + gluten:true, + ogm:false, + bio:true, + }, + attributes:{ + available:true, + comment:false, + discount:false + }, + pricing: { + stock:10, + price:3.80, + discount:3.0, + part:'0.75L' + }, + categories: c.Categories[2]._id, + vendor:'515ec12e56a8d5961e000004' + },{ + _id : new ObjectId(), + sku:1000004, + title: "Product 4 with cat", + details:{ + description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ", + comment:"Temps de cuisson : 16 minutes", + gluten:true, + ogm:false, + bio:true, + }, + attributes:{ + available:true, + comment:false, + discount:false + }, + pricing: { + stock:10, + price:3.80, + discount:3.0, + part:'0.75L' + }, + categories: c.Categories[2]._id, + vendor:'515ec12e56a8d5961e000005' + },{ + _id : new ObjectId(), + sku:1000005, + title: "Product not in stock", + details:{ + description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ", + comment:"Temps de cuisson : 16 minutes", + gluten:true, + ogm:false, + bio:true, + }, + attributes:{ + available:true, + comment:false, + discount:false + }, + pricing: { + stock:5, + price:3.80, + discount:3.0, + part:'0.75L' + }, + categories: c.Categories[2]._id, + vendor:'515ec12e56a8d5961e000004' + } +]; + + + diff --git a/test/fixtures/Orders.report.discount.js b/test/fixtures/Orders.report.discount.js new file mode 100644 index 0000000..aede8bb --- /dev/null +++ b/test/fixtures/Orders.report.discount.js @@ -0,0 +1,751 @@ +var ObjectId = require('mongodb').ObjectID; +var c=require('./Categories'); +var u=require('./Users'); +var orders = require('mongoose').model('Orders'); + +// this fixture focus on order with +// - different dates (today, next shipping day, next week), +// - config.shared.financialstatus ("pending","authorized","partially_paid","paid", "partially_refunded" ...) +// - config.shared.cancelreason ("customer", "fraud", "inventory", "other") +// - config.shared.status ("fulfilled","partial","fulfilled", "shipped","failure") +// +// build orders with +// - 2 users +// - all products, stock, shop, user ... are available +// - + +var oneweek=orders.findOneWeekOfShippingDay(); +var firstDayOfMonth=orders.findCurrentShippingDay(); +var lastDayOfMonth=new Date(firstDayOfMonth); +var customerDay=oneweek[0]; + +var passedday=new Date(customerDay.getTime()-86400000*7) + +lastDayOfMonth.setDate(lastDayOfMonth.daysInMonth()); +lastDayOfMonth.setHours(22,0,0,0); + +firstDayOfMonth.setDate(1); +firstDayOfMonth.setHours(16,0,0,0); + +exports.Orders=[ + { + _id: ObjectId("52f12f09a328f285313bda10"), + oid: 2100000, + /* customer */ + customer: u.Users[1], + + /* email customer */ + email: "evaleto@gmail.com", + + /* payment */ + payment: { + issuer: "visa", + number:'98xxxxxxx4123', + alias:'01234567890', + status:"voided" + }, + + /* shipping adresse*/ + shipping: { + name: "famille olivier evalet 1", + note: "123456", + streetAdress: "route de chêne 34", + floor: "2", + postalCode: "1208", + region: "Genève", + when: lastDayOfMonth, + geo: { lat: 46.1997473, lng: 6.1692497} + }, + + items: [ + { + sku: 1000001, + title: "Product 1 with cat", + quantity: 3, + price: 2.5, + part: "1pce", + note: "", + finalprice: 10, + category: "Viande", + vendor:"un-autre-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + }, + { + sku: 1000002, + title: "Product 2 with cat", + quantity: 3, + price: 3, + part: "100gr", + note: "", + finalprice: 10, + category: "Fruits", + vendor:"un-autre-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + } + ], + + + /* vendors */ + vendors: [ + { + /* shop available !=true */ + ref: ObjectId('515ec12e56a8d5961e000004'), + slug: "un-autre-shop", + name: "un autre shop", + address: "TODO", + discount:{ + amount:.5, + finalAmount:1.0 + }, + fees:.14 + } + ], + + fulfillments: { + status: "failure" + }, + + created: new Date(), + closed:passedday + }, + { + _id: ObjectId("52f12f09a328f285313bda00"), + oid: 2000006, + /* customer */ + customer: u.Users[1], + + /* email customer */ + email: "evaleto@gmail.com", + + /* payment */ + payment: { + issuer: "tester", + number:'98xxxxxxx4123', + alias:'01234567890', + status:"paid" + }, + + fulfillments: { + status: "fulfilled" + }, + + /* shipping adresse*/ + shipping: { name: "famille olivier evalet 1", note: "123456", streetAdress: "route de chêne 34", floor: "2", postalCode: "1208", region: "Genève", when: firstDayOfMonth, geo: { lat: 46.1997473, lng: 6.1692497}}, + + /* vendors */ + vendors: [ + { + /*shop status !=true */ + ref: ObjectId('515ec12e56a8d5961e000006'), + slug: "super-shop", + name: "super shop", + address: "TODO", + fees:.16 + }, + { + /* shop available !=true */ + ref: ObjectId('515ec12e56a8d5961e000004'), + slug: "un-autre-shop", + name: "un autre shop", + address: "TODO", + discount:{ + amount:.5, + finalAmount:.5 + }, + fees:.14 + } + ], + /* items */ + items: [ + { + sku: 1000001, + title: "Product 1 with cat", + quantity: 3, + price: 2.5, + part: "1pce", + note: "", + finalprice: 10, + category: "Viande", + vendor:"super-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + }, + { + sku: 1000002, + title: "Product 2 with cat", + quantity: 3, + price: 3, + part: "100gr", + note: "", + finalprice: 10, + category: "Fruits", + vendor:"un-autre-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + }, + { + sku: 1000002, + title: "Product 2 with cat", + quantity: 1, + price: 3, + part: "100gr", + note: "", + finalprice: 1, + category: "Fruits", + vendor:"un-autre-shop", + variant:{ + title:'Variation A' + }, + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + } + ], + + + closed:passedday, + created: new Date() + },{ + + _id: ObjectId("52f12f09a328f285313bda01"), + oid: 2000007, + /* customer */ + customer: u.Users[2], + + /* email customer */ + email: "delphine@gmail.com", + + /* payment */ + payment: { + issuer: "mastercard", + number:'98xxxxxxx4123', + alias:'01234567890', + status:"paid" + }, + + fulfillments: { + status: "fulfilled" + }, + + /* shipping adresse*/ + shipping: { + name: "famille olivier evalet 1", + note: "123456", + streetAdress: "route de chêne 34", floor: "2", postalCode: "1208", region: "Genève", + when: firstDayOfMonth, geo: { lat: 46.1997473, lng: 6.1692497} + }, + + /* vendors */ + vendors: [ + { + ref: ObjectId('515ec12e56a8d5961e000004'), + slug: "un-autre-shop", + name: "Un autre shop", + address: "TODO", + discount:{ + amount:.5, + finalAmount:1.0 + }, + fees:.14 + }, + { + /*shop status !=true */ + ref: ObjectId('515ec12e56a8d5961e000005'), + slug: "mon-shop", + name: "mon shop", + address: "TODO", + discount:{ + amount:.5, + finalAmount:.5 + }, + fees:.15 + } + ], + /* items */ + items: [ + { + sku: 1000004, + title: "Product 4 with cat", + quantity: 1, + price: 2.5, + part: "1pce", + note: "", + finalprice: 10, + category: "Viande", + vendor:"mon-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + }, + { + sku: 1000002, + title: "Product 2 with cat", + quantity: 3, + price: 3, + part: "100gr", + note: "", + finalprice: 10, + category: "Fruits", + vendor:"un-autre-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + }, + { + sku: 1000003, + title: "Product 3 with cat", + quantity: 2, + price: 7.6, + part: "0.75L", + note: "", + finalprice: 15, + category: "Poissons", + vendor:"un-autre-shop", + fulfillment: { + shipping: "grouped", + status: "failure" + } + } + ], + + + created: new Date(), + closed:passedday + + },{ + + _id: ObjectId("52f12f09a328f285313bda02"), + oid: 2000008, + /* customer */ + customer: u.Users[1], + + /* email customer */ + email: "evaleto@gmail.com", + + /* payment */ + payment: { + issuer: "tester", + number:'98xxxxxxx4123', + alias:'01234567890', + status:"paid" + }, + + fulfillments: { + status: "fulfilled" + }, + + /* shipping adresse*/ + shipping: { + name: "famille olivier evalet 1", + note: "123456", + streetAdress: "route de chêne 34", floor: "2", postalCode: "1208", region: "Genève", + when: lastDayOfMonth, geo: { lat: 46.1997473, lng: 6.1692497} + }, + + /* vendors */ + vendors: [ + { + ref: ObjectId('515ec12e56a8d5961e000004'), + slug: "un-autre-shop", + name: "Un autre shop", + address: "TODO", + fees:.14 + }, + { + /*shop status !=true */ + ref: ObjectId('515ec12e56a8d5961e000005'), + slug: "mon-shop", + name: "mon shop", + address: "TODO", + fees:.30 + } + ], + /* items */ + items: [ + { + sku: 1000004, + title: "Product 4 with cat", + quantity: 1, + price: 2.5, + part: "1pce", + note: "", + finalprice: 2.5, + category: "Viande", + vendor:"mon-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + }, + { + sku: 1000002, + title: "Product 2 with cat", + quantity: 3, + price: 3, + part: "100gr", + note: "", + finalprice: 9, + category: "Fruits", + vendor:"un-autre-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + }, + { + sku: 1000003, + title: "Product 3 with cat", + quantity: 2, + price: 7.6, + part: "0.75L", + note: "", + finalprice: 15, + category: "Poissons", + vendor:"un-autre-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + } + ], + + + created: lastDayOfMonth, + closed:passedday + + },{ + + _id: ObjectId("52f12f09a328f285313bda03"), + oid: 2000009, + /* customer */ + customer: u.Users[1], + + /* email customer */ + email: "evaleto@gmail.com", + + /* payment */ + payment: { + issuer: "tester", + number:'98xxxxxxx4123', + alias:'01234567890', + status:"paid" + }, + + fulfillments: { + status: "fulfilled" + }, + + /* shipping adresse*/ + shipping: { + region: "Genève", + when: lastDayOfMonth, + geo: { + lng: 6.1692497, + lat: 46.1997473 + }, + postalCode: "1204", + location: "Genève-Ville", + floor: "1", + streetAdress: "rue de carouge", + note: "", + name: "famille delphine evalet 4" + }, + + /* vendors */ + vendors: [ + { + ref: ObjectId('515ec12e56a8d5961e000004'), + slug: "un-autre-shop", + name: "Un autre shop", + address: "TODO", + fees:.14 + }, + { + /*shop status !=true */ + ref: ObjectId('515ec12e56a8d5961e000005'), + slug: "mon-shop", + name: "mon shop", + address: "TODO", + fees:.15 + } + ], + /* items */ + items: [ + { + sku: 1000004, + title: "Product 4 with cat", + quantity: 1, + price: 2.5, + part: "1pce", + note: "", + finalprice: 2.5, + category: "Viande", + vendor:"mon-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + }, + { + sku: 1000002, + title: "Product 2 with cat", + quantity: 3, + price: 3, + part: "100gr", + note: "", + finalprice: 3, + category: "Fruits", + vendor:"un-autre-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + }, + { + sku: 1000003, + title: "Product 3 with cat", + quantity: 2, + price: 7.6, + part: "0.75L", + note: "", + finalprice: 7.6, + category: "Poissons", + vendor:"un-autre-shop", + fulfillment: { + shipping: "grouped", + status: "fulfilled" + } + } + ], + + + created: new Date(), + closed:passedday + + } +]; + +// +// ------------------------ SHOPS -------------------------- +// + +exports.Shops=[{ + _id:ObjectId('515ec12e56a8d5961e000004'), + status:true, + name: "Un autre shop", + description:"cool ce shop", + urlpath:"un-autre-shop", + catalog:c.Categories[0]._id, + owner:u.Users[0]._id, + available:{ + active:false, + weekdays:[0,1,2,3,4,5,6] + }, + account:{ + fees:.2 + }, + photo:{ + bg:"http://image.truc.io/bg-01123.jp", + fg:"http://image.truc.io/fg-01123.jp" + } + },{ + _id:ObjectId('515ec12e56a8d5961e000005'), + status:true, + name: "mon shop", + description:"cool ce shop", + urlpath:"mon-shop", + catalog:c.Categories[0]._id, + owner:u.Users[1]._id, + photo:{ + bg:"http://image.truc.io/bg-01123.jp", + fg:"http://image.truc.io/fg-01123.jp" + }, + available:{ + active:false, + weekdays:[0,1,2,3,4,5,6] + } + },{ + _id:ObjectId('515ec12e56a8d5961e000006'), + status:true, + name: "super shop", + description:"super shop", + urlpath:"super-shop", + catalog:c.Categories[0]._id, + owner:u.Users[0]._id, + available:{ + active:false, + weekdays:[0,1,2,3,4,5,6] + }, + photo:{ + bg:"http://image.truc.io/bg-01123.jp", + fg:"http://image.truc.io/fg-01123.jp" + } + },{ + _id:ObjectId('515ec12e56a8d5961e000017'), + status:true, + name: "un shop", + description:"cool ce shop", + urlpath:"un-shop", + catalog:c.Categories[0]._id, + owner:u.Users[1]._id, + photo:{ + bg:"http://image.truc.io/bg-01123.jp", + fg:"http://image.truc.io/fg-01123.jp" + }, + available:{ + active:false, + weekdays:[0,1,2,3,4,5,6] + } + } +]; + +// +// ------------------------ PRODUCTS -------------------------- +// + +exports.Products=[{ + _id : new ObjectId(), + sku:1000001, + title: "Product 2 with cat", + details:{ + description:"description", + comment:"Temps de cuisson : 16 minutes", + gluten:true, + ogm:false, + bio:false, + }, + + attributes:{ + available:true, + comment:false, + discount:true + }, + + pricing: { + stock:10, + price:3.80, + discount:3.0, + part:'100gr' + }, + /* weight:0,1 */ + categories: c.Categories[1]._id, + //un-autre-shop, id:0004, status:true, owner:gluck + vendor:'515ec12e56a8d5961e000006' + },{ + _id : new ObjectId(), + sku:1000002, + title: "Product 2 with cat", + details:{ + description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ", + comment:"Temps de cuisson : 16 minutes", + gluten:true, + ogm:true, + bio:true, + }, + attributes:{ + available:true, + comment:false, + discount:false + }, + variants:[ + {title:'Variation A'} + ], + pricing: { + stock:10, + price:3.80, + part:'0.75L' + }, + /* weight:2 */ + categories: c.Categories[3]._id, + //shop available==true, status!=true + vendor:'515ec12e56a8d5961e000004' + },{ + _id : new ObjectId(), + sku:1000003, + title: "Product 3 with cat", + details:{ + description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ", + comment:"Temps de cuisson : 16 minutes", + gluten:true, + ogm:false, + bio:true, + }, + attributes:{ + available:true, + comment:false, + discount:false + }, + pricing: { + stock:10, + price:3.80, + discount:3.0, + part:'0.75L' + }, + categories: c.Categories[2]._id, + vendor:'515ec12e56a8d5961e000004' + },{ + _id : new ObjectId(), + sku:1000004, + title: "Product 4 with cat", + details:{ + description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ", + comment:"Temps de cuisson : 16 minutes", + gluten:true, + ogm:false, + bio:true, + }, + attributes:{ + available:true, + comment:false, + discount:false + }, + pricing: { + stock:10, + price:3.80, + discount:3.0, + part:'0.75L' + }, + categories: c.Categories[2]._id, + vendor:'515ec12e56a8d5961e000005' + },{ + _id : new ObjectId(), + sku:1000005, + title: "Product not in stock", + details:{ + description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ", + comment:"Temps de cuisson : 16 minutes", + gluten:true, + ogm:false, + bio:true, + }, + attributes:{ + available:true, + comment:false, + discount:false + }, + pricing: { + stock:5, + price:3.80, + discount:3.0, + part:'0.75L' + }, + categories: c.Categories[2]._id, + vendor:'515ec12e56a8d5961e000004' + } +]; + + + diff --git a/test/fixtures/Orders.repport.js b/test/fixtures/Orders.report.js similarity index 100% rename from test/fixtures/Orders.repport.js rename to test/fixtures/Orders.report.js diff --git a/test/order.create.success.js b/test/order.create.success.js index c0b8ef0..21925ce 100644 --- a/test/order.create.success.js +++ b/test/order.create.success.js @@ -105,6 +105,9 @@ describe("orders.create.success", function(){ // // check shipping fees order.payment.fees.shipping.should.equal(config.shared.shipping.price.hypercenter) + // test gateway[6], + order.payment.fees.charge.should.equal(config.shared.order.gateway[6].fees) + // // check financial status after creation @@ -149,6 +152,13 @@ describe("orders.create.success", function(){ // check that vendor is correct order.vendors.length.should.be.above(1) + // check vendor discount + order.vendors.forEach(function(o,i){ + o.discount.finalAmount.should.equal(0); + }); + order.getTotalDiscount().should.equal(0) + + // check subtotal //config.shared.marketplace.shipping //order.payment.issuer diff --git a/test/order.create.success.withdiscount.js b/test/order.create.success.withdiscount.js new file mode 100644 index 0000000..e39fc97 --- /dev/null +++ b/test/order.create.success.withdiscount.js @@ -0,0 +1,298 @@ +// Use a different DB for tests +var app = require("../app"); + +var db = require('mongoose'); +var dbtools = require("./fixtures/dbtools"); +var should = require("should"); +var data = dbtools.fixtures(["Users.js","Categories.js","Orders.find.js"]); + +var Products=db.model('Products') + , Orders=db.model('Orders') + , Shops=db.model('Shops') + , today=new Date() + , toshortDay + , okDay + , timeoutAndNotPaid=config.shared.order.timeoutAndNotPaid; + + + + + +/** + * create order successfuly : + * - avoid multiple user create order in the same time + * - update all product quantity + * - send email + */ + +describe("orders.create.success.discount", function(){ + var _ = require("underscore"); + + + okDay=Orders.findNextShippingDay(); + toshortDay=Orders.findCurrentShippingDay(); + + // select a shipping time + okDay.setHours(11,0,0,0) + + function updateDiscount(urlpath, discount) { + return Shops.findOneAndUpdate({urlpath:urlpath},{$set:{discount:discount}},{new:true}); + } + + + before(function(done){ + dbtools.clean(function(e){ + dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Orders.find.js"],db,function(err){ + should.not.exist(err); + + // Products.find({}).populate('vendor categories').exec(function(err,ps) { + // ps.forEach(function(p) { + + // p.print(); + // }) + // }) + // Orders.find({}).exec(function(e,os){ + // os.forEach(function(o){ + // o.print(); + // }) + // }) + + done(); + }); + }); + }); + + + after(function(done){ + dbtools.clean(done); + }); + + + it("creating a new order without discount activated", function(done){ + + var customer=data.Users[1]; + var shipping=customer.addresses[0]; + var payment={ + alias:((customer.id+"").hash().crypt()), + issuer:"tester", + number:'12xxxxxxx3456' + }; + var items=[]; + items.push(Orders.prepare(data.Products[1], 3, "")) + items.push(Orders.prepare(data.Products[2], 1, "")) + items.push(Orders.prepare(data.Products[3], 3, "")) + + shipping.when=okDay + shipping.hours=okDay.getHours(); + + + + // + // starting process of order, + // - items, customer, shipping + Orders.create(items, customer, shipping, payment, function(err,order){ + //console.log(order.items[0]) + should.not.exist(err) + + // checking item reservation + order.vendors.forEach(function(o,i){ + o.discount.finalAmount.should.equal(0); + }) + + // check subtotal + order.getTotalDiscount().should.equal(0); + + // check subtotal + order.getSubTotal().should.equal(26.6) + // check total with fees + order.getTotalPrice().should.equal(37.35) + + + done(); + }); + + }); + + it("creating a new order without engough for discount", function(done){ + // update shop for this test + updateDiscount('mon-shop',{active:true,amount:1,threshold:11.41}).exec(function(err,s) { + + var customer=data.Users[1]; + var shipping=customer.addresses[0]; + var payment={ + alias:((customer.id+"").hash().crypt()), + issuer:"tester", + number:'12xxxxxxx3456' + }; + var items=[]; + items.push(Orders.prepare(data.Products[1], 3, "")) + items.push(Orders.prepare(data.Products[2], 1, "")) + items.push(Orders.prepare(data.Products[3], 3, "")) + + shipping.when=okDay + shipping.hours=okDay.getHours(); + + + + // + // starting process of order, + // - items, customer, shipping + Orders.create(items, customer, shipping, payment, function(err,order){ + //console.log(order.items[0]) + should.not.exist(err) + + // checking item reservation + _.findWhere(order.vendors,{slug:'mon-shop'}) + .discount.finalAmount.should.equal(0); + + // check subtotal + order.getTotalDiscount().should.equal(0); + + // check subtotal + order.getSubTotal().should.equal(26.6) + // check total with fees + order.getTotalPrice().should.equal(37.35) + + order.fulfillments.status="failure"; + order.payment.status='voided'; + order.rollbackProductQuantityAndClose('timeout',done); + }); + }); + }); + + it("creating a new order with discount for one shop", function(done){ + // update shop for this test + updateDiscount('mon-shop',{active:true,amount:1,threshold:11.4}).exec(function(err,s) { + + var customer=data.Users[1]; + var shipping=customer.addresses[0]; + var payment={ + alias:((customer.id+"").hash().crypt()), + issuer:"tester", + number:'12xxxxxxx3456' + }; + var items=[]; + items.push(Orders.prepare(data.Products[1], 3, "")) + items.push(Orders.prepare(data.Products[2], 1, "")) + items.push(Orders.prepare(data.Products[3], 3, "")) + + shipping.when=okDay + shipping.hours=okDay.getHours(); + + + + // + // starting process of order, + // - items, customer, shipping + Orders.create(items, customer, shipping, payment, function(err,order){ + //console.log(order.items[0]) + should.not.exist(err) + + // checking item reservation + _.findWhere(order.vendors,{slug:'mon-shop'}) + .discount.finalAmount.should.equal(1); + + // check subtotal + order.getTotalDiscount().should.equal(1); + + // check subtotal + order.getSubTotal().should.equal(26.6) + // check total with fees + order.getTotalPrice().should.equal(36.3) + + order.fulfillments.status="failure"; + order.payment.status='voided'; + order.rollbackProductQuantityAndClose('timeout',done); + }); + }); + }); + + it("creating a new order with cumulated discount for one shop", function(done){ + // update shop for this test + updateDiscount('mon-shop',{active:true,amount:1,threshold:11.40}).exec(function(err,s) { + + var customer=data.Users[1]; + var shipping=customer.addresses[0]; + var payment={ + alias:((customer.id+"").hash().crypt()), + issuer:"tester", + number:'12xxxxxxx3456' + }; + var items=[]; + items.push(Orders.prepare(data.Products[1], 3, "")) + items.push(Orders.prepare(data.Products[2], 1, "")) + items.push(Orders.prepare(data.Products[3], 6, "")) + + shipping.when=okDay + shipping.hours=okDay.getHours(); + + // + // starting process of order, + // - items, customer, shipping + Orders.create(items, customer, shipping, payment, function(err,order){ + // console.log(err,order) + should.not.exist(err) + // checking item reservation + _.findWhere(order.vendors,{slug:'mon-shop'}) + .discount.finalAmount.should.equal(2); + + // check subtotal + order.getTotalDiscount().should.equal(2); + + // check subtotal + order.getSubTotal().should.equal(38) + // check total with fees + order.getTotalPrice().should.equal(46.9) + + order.fulfillments.status="failure"; + order.payment.status='voided'; + order.rollbackProductQuantityAndClose('timeout',done); + }); + }); + }); + + it("creating a new order with cumulated discount for one shop", function(done){ + // update shop for this test + updateDiscount('un-autre-shop',{active:true,amount:1.25,threshold:11.4}).exec(function(err,s) { + + var customer=data.Users[1]; + var shipping=customer.addresses[0]; + var payment={ + alias:((customer.id+"").hash().crypt()), + issuer:"tester", + number:'12xxxxxxx3456' + }; + var items=[]; + items.push(Orders.prepare(data.Products[1], 3, "")) + items.push(Orders.prepare(data.Products[2], 3, "")) + items.push(Orders.prepare(data.Products[3], 6, "")) + + shipping.when=okDay + shipping.hours=okDay.getHours(); + + // + // starting process of order, + // - items, customer, shipping + Orders.create(items, customer, shipping, payment, function(err,order){ + // console.log(err,order) + should.not.exist(err) + // checking item reservation + _.findWhere(order.vendors,{slug:'mon-shop'}) + .discount.finalAmount.should.equal(2); + + _.findWhere(order.vendors,{slug:'un-autre-shop'}) + .discount.finalAmount.should.equal(2.5); + + // check subtotal + order.getTotalDiscount().should.equal(4.5); + + + order.fulfillments.status="failure"; + order.payment.status='voided'; + order.rollbackProductQuantityAndClose('timeout',done); + }); + }); + }); + +}); + diff --git a/test/order.find.product.js b/test/order.find.product.js index 35d5489..5cba429 100644 --- a/test/order.find.product.js +++ b/test/order.find.product.js @@ -33,7 +33,7 @@ describe("orders.find.product", function(){ before(function(done){ dbtools.clean(function(e){ - dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Orders.repport.js"],db,function(err){ + dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Orders.report.js"],db,function(err){ should.not.exist(err); // Orders.printInfo() // Orders.find({}).exec(function(e,os){ diff --git a/test/order.report.includeDiscount.js b/test/order.report.includeDiscount.js new file mode 100644 index 0000000..cccc21f --- /dev/null +++ b/test/order.report.includeDiscount.js @@ -0,0 +1,116 @@ +// Use a different DB for tests +var app = require("../app"); + +var db = require('mongoose'); +var dbtools = require("./fixtures/dbtools"); +var should = require("should"); +var util=require("util"); + +var Products=db.model('Products') + , Orders=db.model('Orders') + , criteria={} + , today=new Date() + , toshortDay + , okDay; + + +describe("orders.validate.report", function(){ + var _ = require("underscore"); + + + var oneweek=Orders.findOneWeekOfShippingDay(); + var sellerDay=Orders.findCurrentShippingDay(); + var customerDay=oneweek[0]; + + function setCriteriaDateByMonthAndYear (criteria,month,year) { + criteria.from=new Date() + criteria.from.setDate(1) + criteria.from.setMonth(month) + if(year)criteria.from.setMonth(year); + criteria.from.setHours(1,0,0,0) + + criteria.to=new Date(criteria.from); + criteria.to.setDate(criteria.from.daysInMonth()); + criteria.to.setHours(23,0,0,0); + + } + //price depends on: + //-> item fullfilment != failure + //-> item finalprice + //-> payment gateway + //-> shipping + + before(function(done){ + setCriteriaDateByMonthAndYear(criteria,sellerDay.getMonth()) + + // show !fulfilled items + criteria.showAll=false; + + // TODO those 2 criterias should set by default? + // only fulfilled + criteria.fulfillment='fulfilled'; + // only closed + criteria.closed=true; + + + // restrict to a list of shops + // criteria.shop=req.user.shops.map(function(i){ return i.urlpath}) + + + + dbtools.clean(function(e){ + dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Orders.report.discount.js"],db,function(err){ + should.not.exist(err); + // Orders.find({}).exec(function(e,os){ + // os.forEach(function(o){ + // o.print(); + // }) + // }) + done(); + }); + }); + }); + + + after(function(done){ + dbtools.clean(function(){ + done(); + }); + }); + + // + // + it("report content include discount even for not fulfilled items ", function(done){ + var month=criteria.from.getMonth()+1, year=criteria.from.getFullYear(); + Orders.getCAByVendor({year:year,grouped:true},function (err,report) { + // report.forEach(function(report) { + // console.log('------',report._id.vendor,report.items,report.amount,report.fees,report.orders) + // }) + // console.log(JSON.stringify(results,0,2)); + // console.log('---------',report.shops['mon-shop']) + // console.log('---------',report.shops['super-shop']) + // console.log('---------ca ',report.shops['un-autre-shop'].amount) + // console.log('---------fees',report.shops['un-autre-shop'].fees) + // console.log('---------disc',report.shops['un-autre-shop'].discount) + // + // not fulfilled should keep discount! + report.shops['mon-shop'].discount.should.equal(0.5); + report.shops['super-shop'].discount.should.equal(0); + report.shops['un-autre-shop'].discount.should.equal(1.5); + + // + // validate fees after discount reduction + var fees=(report.shops['un-autre-shop'].amount-report.shops['un-autre-shop'].discount)*report.shops['un-autre-shop'].contractFees[0]; + report.shops['un-autre-shop']. + fees.should.equal(parseFloat(fees.toFixed(2))) + + done(); + }); + }); + + + + + +}); + diff --git a/test/order.validate.price.js b/test/order.validate.price.js index 3ac6b32..14dd6bb 100644 --- a/test/order.validate.price.js +++ b/test/order.validate.price.js @@ -49,7 +49,7 @@ describe("orders.validate.price", function(){ }); it("check order price (visa+items+shipping saved with 0) ", function(done){ - db.model('Orders').find({oid:2100000}, function(err,order){ + db.model('Orders').find({oid:2100000}).populate('+vendors.discount.finalAmount').exec(function(err,order){ should.not.exist(err) // item!='failure' => E(item.price) + gateway fees + shipping fees // this order contains only shipping @@ -59,7 +59,7 @@ describe("orders.validate.price", function(){ }); it("check order price (+items+shipping) ", function(done){ - db.model('Orders').find({oid:2000006}, function(err,order){ + db.model('Orders').find({oid:2000006}).populate('+vendors.discount.finalAmount').exec(function(err,order){ should.not.exist(err) order[0].getTotalPrice().should.equal(30.6) done(); @@ -68,7 +68,7 @@ describe("orders.validate.price", function(){ it("check order price (+items(failure)+ full shipping) ", function(done){ - db.model('Orders').find({oid:2000007}, function(err,order){ + db.model('Orders').find({oid:2000007}).populate('+vendors.discount.finalAmount').exec(function(err,order){ should.not.exist(err) order[0].getSubTotal().should.equal(10); order[0].getTotalPrice().should.equal(20.6); @@ -79,7 +79,7 @@ describe("orders.validate.price", function(){ it("check order 145fr got special shipping price ", function(done){ - db.model('Orders').find({oid:2000008}, function(err,order){ + db.model('Orders').find({oid:2000008}).populate('+vendors.discount.finalAmount').exec(function(err,order){ should.not.exist(err) order[0].getSubTotal().should.equal(145); order[0].getTotalPrice().should.equal(153); @@ -89,7 +89,7 @@ describe("orders.validate.price", function(){ }); it("check order 180fr got special shipping price ", function(done){ - db.model('Orders').find({oid:2000009}, function(err,order){ + db.model('Orders').find({oid:2000009}).populate('+vendors.discount.finalAmount').exec(function(err,order){ should.not.exist(err) order[0].getSubTotal().should.equal(180); order[0].getTotalPrice().should.equal(193.8); @@ -101,7 +101,7 @@ describe("orders.validate.price", function(){ it("check order shipping half shipping price even with 180CHF", function(done){ // this way you disabled the discountB config.shared.shipping.discountB=0; - db.model('Orders').find({oid:2000009}, function(err,order){ + db.model('Orders').find({oid:2000009}).populate('+vendors.discount.finalAmount').exec(function(err,order){ should.not.exist(err) order[0].getSubTotal().should.equal(180); order[0].getTotalPrice().should.equal(188.7); diff --git a/test/order.validate.report.022016.js b/test/order.validate.report.022016.js new file mode 100644 index 0000000..0bcba97 --- /dev/null +++ b/test/order.validate.report.022016.js @@ -0,0 +1,119 @@ +// Use a different DB for tests +var app = require("../app"); + +var db = require('mongoose'); +var dbtools = require("./fixtures/dbtools"); +var should = require("should"); +var util=require("util"); + +var Products=db.model('Products') + , Orders=db.model('Orders') + , criteria={} + , today=new Date() + , toshortDay + , okDay; + + +describe("orders.validate.report.022016", function(){ + var _ = require("underscore"); + + + var oneweek=Orders.findOneWeekOfShippingDay(); + var sellerDay=Orders.findCurrentShippingDay(); + var customerDay=oneweek[0]; + + function setCriteriaDateByMonthAndYear (criteria,month,year) { + criteria.from=new Date() + criteria.from.setDate(1) + criteria.from.setMonth(month) + if(year)criteria.from.setMonth(year); + criteria.from.setHours(1,0,0,0) + + criteria.to=new Date(criteria.from); + criteria.to.setDate(criteria.from.daysInMonth()); + criteria.to.setHours(23,0,0,0); + + } + //price depends on: + //-> item fullfilment != failure + //-> item finalprice + //-> payment gateway + //-> shipping + + before(function(done){ + setCriteriaDateByMonthAndYear(criteria,sellerDay.getMonth()) + + // show !fulfilled items + criteria.showAll=false; + + // TODO those 2 criterias should set by default? + // only fulfilled + criteria.fulfillment='fulfilled'; + // only closed + criteria.closed=true; + + + // restrict to a list of shops + // criteria.shop=req.user.shops.map(function(i){ return i.urlpath}) + + + + dbtools.clean(function(e){ + dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Orders.report.022016.js"],db,function(err){ + should.not.exist(err); + // Orders.find({'payment.status':'paid'}).exec(function(e,os){ + // var oid=os.map(function(o) { + // return o.oid + // }); + // os.forEach(function(o){ + // o.print(); + // }) + + // }) + done(); + }); + }); + }); + + + after(function(done){ + dbtools.clean(function(){ + done(); + }); + }); + + + // + // + it("validate report content with the new API 2.0 for Year", function(done){ + var month=criteria.from.getMonth()+1, year=criteria.from.getFullYear(); + Orders.getCAByVendor({year:year,grouped:true},function (err,report) { + + + report.shops['purogusto'].items.should.equal(48); + report.shops['purogusto'].amount.should.equal(396); + report.shops['purogusto'].orders.length.should.equal(20); + report.shops['purogusto'].fees.should.equal(71.28); + report.shops['purogusto'].contractFees[0].should.equal(0.18); + + report.shops['les-fromages-de-gaetan'].items.should.equal(83); + report.shops['les-fromages-de-gaetan'].amount.should.equal(532.45); + report.shops['les-fromages-de-gaetan'].orders.length.should.equal(29); + report.shops['les-fromages-de-gaetan'].fees.should.equal(79.87); + report.shops['les-fromages-de-gaetan'].contractFees[0].should.equal(0.15); + + // report.shops['purogusto'].products.length.should.equal(48); + report.orders.length.should.equal(39); + + + done(); + }); + }); + + + + + + +}); + diff --git a/test/order.validate.report.js b/test/order.validate.report.js new file mode 100644 index 0000000..1309472 --- /dev/null +++ b/test/order.validate.report.js @@ -0,0 +1,241 @@ +// Use a different DB for tests +var app = require("../app"); + +var db = require('mongoose'); +var dbtools = require("./fixtures/dbtools"); +var should = require("should"); +var util=require("util"); + +var Products=db.model('Products') + , Orders=db.model('Orders') + , criteria={} + , today=new Date() + , toshortDay + , okDay; + + +describe("orders.validate.report", function(){ + var _ = require("underscore"); + + + var oneweek=Orders.findOneWeekOfShippingDay(); + var sellerDay=Orders.findCurrentShippingDay(); + var customerDay=oneweek[0]; + + function setCriteriaDateByMonthAndYear (criteria,month,year) { + criteria.from=new Date() + criteria.from.setDate(1) + criteria.from.setMonth(month) + if(year)criteria.from.setMonth(year); + criteria.from.setHours(1,0,0,0) + + criteria.to=new Date(criteria.from); + criteria.to.setDate(criteria.from.daysInMonth()); + criteria.to.setHours(23,0,0,0); + + } + //price depends on: + //-> item fullfilment != failure + //-> item finalprice + //-> payment gateway + //-> shipping + + before(function(done){ + setCriteriaDateByMonthAndYear(criteria,sellerDay.getMonth()) + + // show !fulfilled items + criteria.showAll=false; + + // TODO those 2 criterias should set by default? + // only fulfilled + criteria.fulfillment='fulfilled'; + // only closed + criteria.closed=true; + + + // restrict to a list of shops + // criteria.shop=req.user.shops.map(function(i){ return i.urlpath}) + + + + dbtools.clean(function(e){ + dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Orders.report.js"],db,function(err){ + should.not.exist(err); + // Orders.find({}).exec(function(e,os){ + // os.forEach(function(o){ + // o.print(); + // }) + // }) + done(); + }); + }); + }); + + + after(function(done){ + dbtools.clean(function(){ + done(); + }); + }); + + it("validate report content ", function(done){ + + // + // order 2000006 contains variation on + // -> item 1000002 [un-autre-shop] + 1.- + + Orders.generateRepportForShop(criteria,function(err,report){ + should.not.exist(err) + // Object.keys(report.shops).forEach(function (slug) { + // console.log('-----',slug,report.shops[slug]) + // }) + + + report.shops['mon-shop'].monthitems.should.equal(2); + report.shops['mon-shop'].monthamount.should.equal(5); + report.shops['mon-shop'].monthorders.should.equal(2); + + // fees are changing for mon-shop + //-------- mon-shop 2.5 0.15 0.375 + //last day mon-shop 2.5 0.3 0.75 + report.shops['mon-shop'].monthfees.should.equal(1.13); + report.shops['mon-shop'].details.fees.should.equal(0.3); + + report.shops['super-shop'].monthitems.should.equal(3); + report.shops['super-shop'].monthamount.should.equal(10); + report.shops['super-shop'].monthorders.should.equal(1); + report.shops['super-shop'].monthfees.should.equal(1.6); + report.shops['super-shop'].details.fees.should.equal(0.16); + + report.shops['un-autre-shop'].monthitems.should.equal(17); + report.shops['un-autre-shop'].monthamount.should.equal(55.6); + report.shops['un-autre-shop'].monthorders.should.equal(4); + report.shops['un-autre-shop'].monthfees.should.equal(7.78); + report.shops['un-autre-shop'].details.fees.should.equal(0.14); + report.monthamount.should.equal(70.6); + // fees are changing for mon-shop + //-------- mon-shop total was 9.99 + 0.375 + report.monthca.should.equal(10.51); + report.monthitems.should.equal(22); + report.monthorders.should.equal(4); + + // item!='failure' => E(item.price) + gateway fees + shipping fees + // this order contains only shipping + done(); + }); + }); + + // + // + it("validate report content with the new API 2.0 for Year", function(done){ + var month=criteria.from.getMonth()+1, year=criteria.from.getFullYear(); + Orders.getCAByVendor({year:year,grouped:true},function (err,report) { + report.shops['mon-shop'].items.should.equal(2); + report.shops['mon-shop'].amount.should.equal(5); + report.shops['mon-shop'].orders.length.should.equal(2); + report.shops['mon-shop'].fees.should.equal(1.13); + report.shops['mon-shop'].contractFees.sort()[0].should.equal(0.15); + report.shops['mon-shop'].contractFees.sort()[1].should.equal(0.3); + report.shops['mon-shop'].products.length.should.equal(1); + report.shops['mon-shop'].products[0].count.should.equal(1); + report.shops['mon-shop'].products[0].amount.should.equal(2.5); + + report.shops['super-shop'].items.should.equal(3); + report.shops['super-shop'].amount.should.equal(10); + report.shops['super-shop'].orders.length.should.equal(1); + report.shops['super-shop'].fees.should.equal(1.6); + report.shops['super-shop'].contractFees[0].should.equal(0.16); + + report.shops['un-autre-shop'].items.should.equal(17); + report.shops['un-autre-shop'].amount.should.equal(55.6); + report.shops['un-autre-shop'].orders.length.should.equal(4); + report.shops['un-autre-shop'].fees.should.equal(7.78); + report.shops['un-autre-shop'].contractFees[0].should.equal(0.14); + report.shops['un-autre-shop'].products.length.should.equal(7); + report.amount.should.equal(70.6); + report.ca.should.equal(10.51); + report.items.should.equal(22); + report.orders.length.should.equal(4); + report.products.length.should.equal(4); + + + done(); + }); + }); + + // + // + it("validate report content with the new API 2.0 for Month", function(done){ + var month=criteria.from.getMonth()+1, year=criteria.from.getFullYear(); + Orders.getCAByVendor({month:month,grouped:true},function (err,report) { + + done(); + }); + }); + + it("validate report content with the new API 1.0", function(done){ + + // + // order 2000006 contains variation on + // -> item 1000002 [un-autre-shop] + 1.- + var month=criteria.from.getMonth()+1, year=criteria.from.getFullYear(); + Orders.getCAByYearMonthAndVendor({month:month},function (err,report) { + should.not.exist(err) + + + report[year][month]['mon-shop'].items.should.equal(2); + report[year][month]['mon-shop'].amount.should.equal(5); + report[year][month]['mon-shop'].orders.length.should.equal(2); + report[year][month]['mon-shop'].fees.should.equal(1.13); + report[year][month]['mon-shop'].contractFees.length.should.equal(2); + + // FIXME select vendor fees TODO travis dont get the same value 0.15 vs 0.30 + //report[year][month]['mon-shop'].details.fees.should.equal(0.3); + report[year][month]['super-shop'].items.should.equal(3); + report[year][month]['super-shop'].amount.should.equal(10); + report[year][month]['super-shop'].orders.length.should.equal(1); + report[year][month]['super-shop'].fees.should.equal(1.6); + report[year][month]['super-shop'].contractFees[0].should.equal(0.16); + + report[year][month]['un-autre-shop'].items.should.equal(17); + report[year][month]['un-autre-shop'].amount.should.equal(55.6); + report[year][month]['un-autre-shop'].orders.length.should.equal(4); + report[year][month]['un-autre-shop'].fees.should.equal(7.78); + report[year][month]['un-autre-shop'].contractFees[0].should.equal(0.14); + + + // report[year][month].fees.should.equal(10.51); + // report[year][month].items.should.equal(22); + // report[year][month].orders.should.equal(4); + + done(); + }) + + }); + + + + it.skip("validate report content for unknown year ", function(done){ + setCriteriaDateByMonthAndYear(criteria,sellerDay.getMonth(),1989) + + Orders.generateRepportForShop(criteria,function(err,report){ + should.not.exist(err) + + report.monthamount.should.equal(0); + report.monthca.should.equal(0); + report.monthitems.should.equal(0); + report.monthorders.should.equal(0); + + + // item!='failure' => E(item.price) + gateway fees + shipping fees + // this order contains only shipping + done(); + }); + }); + + + + + +}); + diff --git a/test/order.validate.repport.js b/test/order.validate.repport.js deleted file mode 100644 index 28bcfe9..0000000 --- a/test/order.validate.repport.js +++ /dev/null @@ -1,194 +0,0 @@ -// Use a different DB for tests -var app = require("../app"); - -var db = require('mongoose'); -var dbtools = require("./fixtures/dbtools"); -var should = require("should"); - -var Products=db.model('Products') - , Orders=db.model('Orders') - , criteria={} - , today=new Date() - , toshortDay - , okDay; - - -describe("orders.validate.repport", function(){ - var _ = require("underscore"); - - - var oneweek=Orders.findOneWeekOfShippingDay(); - var sellerDay=Orders.findCurrentShippingDay(); - var customerDay=oneweek[0]; - - function setCriteriaDateByMonthAndYear (criteria,month,year) { - criteria.from=new Date() - criteria.from.setDate(1) - criteria.from.setMonth(month) - if(year)criteria.from.setMonth(year); - criteria.from.setHours(1,0,0,0) - - criteria.to=new Date(criteria.from); - criteria.to.setDate(criteria.from.daysInMonth()); - criteria.to.setHours(23,0,0,0); - - } - //price depends on: - //-> item fullfilment != failure - //-> item finalprice - //-> payment gateway - //-> shipping - - before(function(done){ - setCriteriaDateByMonthAndYear(criteria,sellerDay.getMonth()) - - // show !fulfilled items - criteria.showAll=false; - - // TODO those 2 criterias should set by default? - // only fulfilled - criteria.fulfillment='fulfilled'; - // only closed - criteria.closed=true; - - - // restrict to a list of shops - // criteria.shop=req.user.shops.map(function(i){ return i.urlpath}) - - - - dbtools.clean(function(e){ - dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Orders.repport.js"],db,function(err){ - should.not.exist(err); - // Orders.find({}).exec(function(e,os){ - // os.forEach(function(o){ - // o.print(); - // }) - // }) - done(); - }); - }); - }); - - - after(function(done){ - dbtools.clean(function(){ - done(); - }); - }); - - it("validate repport content ", function(done){ - - // - // order 2000006 contains variation on - // -> item 1000002 [un-autre-shop] + 1.- - - Orders.generateRepportForShop(criteria,function(err,repport){ - should.not.exist(err) - // Object.keys(repport.shops).forEach(function (slug) { - // console.log('-----',slug,repport.shops[slug]) - // }) - - - repport.shops['mon-shop'].monthitems.should.equal(2); - repport.shops['mon-shop'].monthamount.should.equal(5); - repport.shops['mon-shop'].monthorders.should.equal(2); - - // fees are changing for mon-shop - //-------- mon-shop 2.5 0.15 0.375 - //last day mon-shop 2.5 0.3 0.75 - repport.shops['mon-shop'].monthfees.should.equal(1.13); - repport.shops['mon-shop'].details.fees.should.equal(0.3); - - repport.shops['super-shop'].monthitems.should.equal(3); - repport.shops['super-shop'].monthamount.should.equal(10); - repport.shops['super-shop'].monthorders.should.equal(1); - repport.shops['super-shop'].monthfees.should.equal(1.6); - repport.shops['super-shop'].details.fees.should.equal(0.16); - - repport.shops['un-autre-shop'].monthitems.should.equal(17); - repport.shops['un-autre-shop'].monthamount.should.equal(55.6); - repport.shops['un-autre-shop'].monthorders.should.equal(4); - repport.shops['un-autre-shop'].monthfees.should.equal(7.78); - repport.shops['un-autre-shop'].details.fees.should.equal(0.14); - repport.monthamount.should.equal(70.6); - // fees are changing for mon-shop - //-------- mon-shop total was 9.99 + 0.375 - repport.monthca.should.equal(10.51); - repport.monthitems.should.equal(22); - repport.monthorders.should.equal(4); - - - - // item!='failure' => E(item.price) + gateway fees + shipping fees - // this order contains only shipping - done(); - }); - }); - - - it("validate repport content with the new API", function(done){ - - // - // order 2000006 contains variation on - // -> item 1000002 [un-autre-shop] + 1.- - var month=criteria.from.getMonth()+1, year=criteria.from.getFullYear(); - Orders.getCAByYearMonthAndVendor({month:month},function (err,repport) { - should.not.exist(err) - - - repport[year][month]['mon-shop'].items.should.equal(2); - repport[year][month]['mon-shop'].amount.should.equal(5); - repport[year][month]['mon-shop'].orders.should.equal(2); - repport[year][month]['mon-shop'].fees.should.equal(1.13); - - // FIXME select vendor fees TODO travis dont get the same value 0.15 vs 0.30 - //repport[year][month]['mon-shop'].details.fees.should.equal(0.3); - - repport[year][month]['super-shop'].items.should.equal(3); - repport[year][month]['super-shop'].amount.should.equal(10); - repport[year][month]['super-shop'].orders.should.equal(1); - repport[year][month]['super-shop'].fees.should.equal(1.6); - repport[year][month]['super-shop'].details.fees.should.equal(0.16); - - repport[year][month]['un-autre-shop'].items.should.equal(17); - repport[year][month]['un-autre-shop'].amount.should.equal(55.6); - repport[year][month]['un-autre-shop'].orders.should.equal(4); - repport[year][month]['un-autre-shop'].fees.should.equal(7.78); - repport[year][month]['un-autre-shop'].details.fees.should.equal(0.14); - - repport[year][month].fees.should.equal(10.51); - repport[year][month].items.should.equal(22); - repport[year][month].orders.should.equal(4); - - done(); - }) - - }); - - - - it("validate repport content for unknown year ", function(done){ - setCriteriaDateByMonthAndYear(criteria,sellerDay.getMonth(),1989) - - Orders.generateRepportForShop(criteria,function(err,repport){ - should.not.exist(err) - - repport.monthamount.should.equal(0); - repport.monthca.should.equal(0); - repport.monthitems.should.equal(0); - repport.monthorders.should.equal(0); - - - // item!='failure' => E(item.price) + gateway fees + shipping fees - // this order contains only shipping - done(); - }); - }); - - - - - -}); -