You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
611 lines
17 KiB
611 lines
17 KiB
package controller;
|
|
|
|
import db.UserContract;
|
|
import sugoi.form.elements.DateDropdowns;
|
|
import sugoi.form.elements.Input;
|
|
import sugoi.form.elements.Selectbox;
|
|
import sugoi.form.Form;
|
|
import db.Contract;
|
|
import Common;
|
|
import plugin.Tutorial;
|
|
|
|
using Std;
|
|
|
|
import service.OrderService;
|
|
|
|
class Contract extends Controller {
|
|
public function new() {
|
|
super();
|
|
}
|
|
|
|
@tpl("contract/view.mtt")
|
|
public function doView(c:db.Contract) {
|
|
view.category = 'amap';
|
|
view.c = c;
|
|
}
|
|
|
|
/**
|
|
* "my account" page
|
|
*/
|
|
@tpl("contract/default.mtt")
|
|
function doDefault() {
|
|
// Create the list of links to change the language
|
|
var langs = App.config.get("langs", "fr").split(";");
|
|
var langNames = App.config.get("langnames", "Français").split(";");
|
|
var i = 0;
|
|
var langLinks = "";
|
|
for (lang in langs) {
|
|
langLinks += "<li><a href=\"?lang=" + langs[i] + "\">" + langNames[i] + "</a></li>";
|
|
i++;
|
|
}
|
|
view.langLinks = langLinks;
|
|
view.langText = langNames[langs.indexOf(app.session.lang)];
|
|
|
|
// change account lang
|
|
if (app.params.exists("lang") && app.user != null) {
|
|
app.user.lock();
|
|
app.user.lang = app.params.get("lang");
|
|
app.user.update();
|
|
}
|
|
|
|
var ua = db.UserAmap.get(app.user, app.user.amap);
|
|
if (ua == null)
|
|
throw Error("/", t._("You are not a member of this group"));
|
|
|
|
var constOrders = null;
|
|
var varOrders = new Map<String, Array<db.UserContract>>();
|
|
|
|
var a = App.current.user.amap;
|
|
var oneMonthAgo = DateTools.delta(Date.now(), -1000.0 * 60 * 60 * 24 * 30);
|
|
|
|
// constant orders
|
|
var contracts = db.Contract.manager.search($type == db.Contract.TYPE_CONSTORDERS && $amap == a && $endDate > oneMonthAgo, false);
|
|
constOrders = [];
|
|
for (c in contracts) {
|
|
var orders = app.user.getOrdersFromContracts([c]);
|
|
if (orders.length == 0)
|
|
continue;
|
|
constOrders.push({contract: c, orders: service.OrderService.prepare(orders)});
|
|
}
|
|
|
|
// variable orders, grouped by date
|
|
var contracts = db.Contract.manager.search($type == db.Contract.TYPE_VARORDER && $amap == a && $endDate > oneMonthAgo, false);
|
|
|
|
for (c in contracts) {
|
|
var ds = c.getDistribs(false);
|
|
for (d in ds) {
|
|
// store orders in a stringmap like "2015-01-01" => [order1,order2,...]
|
|
var k = d.date.toString().substr(0, 10);
|
|
var orders = app.user.getOrdersFromDistrib(d);
|
|
if (orders.length > 0) {
|
|
if (!varOrders.exists(k)) {
|
|
varOrders.set(k, Lambda.array(orders));
|
|
} else {
|
|
var z = varOrders.get(k).concat(Lambda.array(orders));
|
|
varOrders.set(k, z);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// final structure
|
|
var varOrders2 = new Array<{date:Date, orders:Array<UserOrder>}>();
|
|
for (k in varOrders.keys()) {
|
|
var d = new Date(k.split("-")[0].parseInt(), k.split("-")[1].parseInt() - 1, k.split("-")[2].parseInt(), 0, 0, 0);
|
|
var orders = service.OrderService.prepare(Lambda.list(varOrders[k]));
|
|
|
|
varOrders2.push({date: d, orders: orders});
|
|
}
|
|
|
|
// sort by date desc
|
|
varOrders2.sort(function(b, a) {
|
|
return Math.round(a.date.getTime() / 1000) - Math.round(b.date.getTime() / 1000);
|
|
});
|
|
|
|
view.varOrders = varOrders2;
|
|
view.constOrders = constOrders;
|
|
|
|
// tutorials
|
|
if (app.user.isAmapManager()) {
|
|
// actions
|
|
if (app.params.exists('startTuto')) {
|
|
// start a tuto
|
|
app.user.lock();
|
|
var t = app.params.get('startTuto');
|
|
app.user.tutoState = {name: t, step: 0};
|
|
app.user.update();
|
|
}
|
|
|
|
// tuto state
|
|
var tutos = new Array<{name:String, completion:Float, key:String}>();
|
|
|
|
for (k in Tutorial.all().keys()) {
|
|
var t = Tutorial.all().get(k);
|
|
|
|
var completion = null;
|
|
if (app.user.tutoState != null && app.user.tutoState.name == k)
|
|
completion = app.user.tutoState.step / t.steps.length;
|
|
|
|
tutos.push({name: t.name, completion: completion, key: k});
|
|
}
|
|
|
|
view.tutos = tutos;
|
|
}
|
|
|
|
// should be able to stop tuto in any case
|
|
if (app.params.exists('stopTuto')) {
|
|
// stopped tuto from a tuto window
|
|
app.user.lock();
|
|
app.user.tutoState = null;
|
|
app.user.update();
|
|
view.stopTuto = true;
|
|
}
|
|
|
|
checkToken();
|
|
view.userAmap = ua;
|
|
}
|
|
|
|
/**
|
|
* Edit a contract
|
|
*/
|
|
@tpl("form.mtt")
|
|
function doEdit(c:db.Contract) {
|
|
view.category = 'contractadmin';
|
|
if (!app.user.isContractManager(c))
|
|
throw Error('/', t._("Forbidden action"));
|
|
|
|
view.title = t._("Edit contract ::contractName::", {contractName: c.name});
|
|
|
|
var group = c.amap;
|
|
var currentContact = c.contact;
|
|
|
|
var form = Form.fromSpod(c);
|
|
form.removeElement(form.getElement("amapId"));
|
|
form.removeElement(form.getElement("type"));
|
|
form.getElement("userId").required = true;
|
|
|
|
app.event(EditContract(c, form));
|
|
|
|
if (form.checkToken()) {
|
|
form.toSpod(c);
|
|
c.amap = group;
|
|
|
|
// checks & warnings
|
|
if (c.hasPercentageOnOrders() && c.percentageValue == null)
|
|
throw Error("/contract/edit/" + c.id, t._("If you would like to add fees to the order, define a rate (%) and a label."));
|
|
|
|
if (c.hasStockManagement()) {
|
|
for (p in c.getProducts()) {
|
|
if (p.stock == null) {
|
|
app.session.addMessage(t._("Warning about management of stock. Please fill the field \"stock\" for all your products"), true);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// no stock mgmt for constant orders
|
|
if (c.hasStockManagement() && c.type == db.Contract.TYPE_CONSTORDERS) {
|
|
c.flags.unset(ContractFlags.StockManagement);
|
|
app.session.addMessage(t._("Managing stock is not available for CSA contracts"), true);
|
|
}
|
|
|
|
c.update();
|
|
|
|
// update rights
|
|
if (c.contact != null && (currentContact == null || c.contact.id != currentContact.id)) {
|
|
var ua = db.UserAmap.get(c.contact, app.user.amap, true);
|
|
ua.giveRight(ContractAdmin(c.id));
|
|
ua.giveRight(Messages);
|
|
ua.giveRight(Membership);
|
|
ua.update();
|
|
|
|
// remove rights to old contact
|
|
if (currentContact != null) {
|
|
var x = db.UserAmap.get(currentContact, c.amap, true);
|
|
if (x != null) {
|
|
x.removeRight(ContractAdmin(c.id));
|
|
x.update();
|
|
}
|
|
}
|
|
}
|
|
|
|
throw Ok("/contractAdmin/view/" + c.id, t._("Contract updated"));
|
|
}
|
|
|
|
view.form = form;
|
|
}
|
|
|
|
@tpl("contract/insertChoose.mtt")
|
|
function doInsertChoose() {
|
|
// checkToken();
|
|
}
|
|
|
|
/**
|
|
* Créé un nouveau contrat
|
|
*/
|
|
@tpl("form.mtt")
|
|
function doInsert(?type:Int) {
|
|
if (!app.user.canManageAllContracts())
|
|
throw Error('/', t._("Forbidden action"));
|
|
if (type == null)
|
|
throw Redirect('/contract/insertChoose');
|
|
|
|
view.title = if (type == db.Contract.TYPE_CONSTORDERS) t._("Create a contract with fixed orders") else t._("Create a contract with variable orders");
|
|
|
|
var c = new db.Contract();
|
|
|
|
var form = Form.fromSpod(c);
|
|
form.removeElement(form.getElement("amapId"));
|
|
form.removeElement(form.getElement("type"));
|
|
form.getElement("userId").required = true;
|
|
|
|
if (form.checkToken()) {
|
|
form.toSpod(c);
|
|
c.amap = app.user.amap;
|
|
// trace(app.user.amap);
|
|
// trace(c.amap);
|
|
c.type = type;
|
|
c.insert();
|
|
|
|
// right
|
|
if (c.contact != null) {
|
|
var ua = db.UserAmap.get(c.contact, app.user.amap, true);
|
|
ua.giveRight(ContractAdmin(c.id));
|
|
ua.giveRight(Messages);
|
|
ua.giveRight(Membership);
|
|
ua.update();
|
|
}
|
|
|
|
throw Ok("/contractAdmin/view/" + c.id, t._("New contract created"));
|
|
}
|
|
|
|
view.form = form;
|
|
}
|
|
|
|
/**
|
|
* Delete a contract (... and its products, orders & distributions)
|
|
*/
|
|
function doDelete(c:db.Contract) {
|
|
if (!app.user.canManageAllContracts())
|
|
throw Error("/contractAdmin", t._("You don't have the authorization to remove a contract"));
|
|
|
|
if (checkToken()) {
|
|
c.lock();
|
|
|
|
// check if there is orders in this contract
|
|
var products = c.getProducts();
|
|
|
|
var orders = db.UserContract.manager.search($productId in Lambda.map(products, function(p) return p.id));
|
|
var qt = 0.0;
|
|
for (o in orders)
|
|
qt += o.quantity; // there could be "zero c qt" orders
|
|
if (qt > 0) {
|
|
throw Error("/contractAdmin", t._("You cannot delete this contract because some orders are linked to it."));
|
|
}
|
|
|
|
// remove admin rights and delete contract
|
|
if (c.contact != null) {
|
|
var ua = db.UserAmap.get(c.contact, c.amap, true);
|
|
if (ua != null) {
|
|
ua.removeRight(ContractAdmin(c.id));
|
|
ua.update();
|
|
}
|
|
}
|
|
|
|
app.event(DeleteContract(c));
|
|
|
|
c.delete();
|
|
throw Ok("/contractAdmin", t._("Contract deleted"));
|
|
}
|
|
|
|
throw Error("/contractAdmin", t._("Token error"));
|
|
}
|
|
|
|
/**
|
|
* Make an order by contract ( standard mode )
|
|
* The form is prepopulated if orders have already been made.
|
|
*
|
|
* It should work for constant orders ( will display one column )
|
|
* or varying orders ( with as many columns as distributions dates )
|
|
*
|
|
*/
|
|
@tpl("contract/order.mtt")
|
|
function doOrder(c:db.Contract) {
|
|
// checks
|
|
if (app.user.amap.hasPayments())
|
|
throw Redirect("/contract/orderAndPay/" + c.id);
|
|
if (app.user.amap.hasShopMode())
|
|
throw Redirect("/shop");
|
|
if (!c.isUserOrderAvailable())
|
|
throw Error("/", t._("This contract is not opened for orders"));
|
|
|
|
var distributions = [];
|
|
// If its a varying contract, we display a column by distribution
|
|
if (c.type == db.Contract.TYPE_VARORDER) {
|
|
distributions = db.Distribution.getOpenToOrdersDeliveries(c);
|
|
} else {
|
|
distributions = [null];
|
|
}
|
|
|
|
// list of distribs with a list of product and optionnaly an order
|
|
var userOrders = new Array<{distrib:db.Distribution, datas:Array<{order:db.UserContract, product:db.Product}>}>();
|
|
var products = c.getProducts();
|
|
|
|
if (c.type == db.Contract.TYPE_VARORDER) {
|
|
for (d in distributions) {
|
|
var datas = [];
|
|
for (p in products) {
|
|
var ua = {order: null, product: p};
|
|
|
|
var order = db.UserContract.manager.select($user == app.user && $productId == p.id && $distributionId == d.id, true);
|
|
|
|
if (order != null)
|
|
ua.order = order;
|
|
datas.push(ua);
|
|
}
|
|
|
|
userOrders.push({distrib: d, datas: datas});
|
|
}
|
|
} else {
|
|
var datas = [];
|
|
for (p in products) {
|
|
var ua = {order: null, product: p};
|
|
|
|
var order = db.UserContract.manager.select($user == app.user && $productId == p.id, true);
|
|
|
|
if (order != null)
|
|
ua.order = order;
|
|
datas.push(ua);
|
|
}
|
|
|
|
userOrders.push({distrib: null, datas: datas});
|
|
}
|
|
|
|
// form check
|
|
if (checkToken()) {
|
|
// get dsitrib if needed
|
|
// var distrib : db.Distribution = null;
|
|
// if (c.type == db.Contract.TYPE_VARORDER) {
|
|
// distrib = db.Distribution.manager.get(Std.parseInt(app.params.get("distribution")), false);
|
|
// }
|
|
|
|
for (k in app.params.keys()) {
|
|
if (k.substr(0, 1) != "d")
|
|
continue;
|
|
var qt = app.params.get(k);
|
|
if (qt == "")
|
|
continue;
|
|
|
|
var pid = null;
|
|
var did = null;
|
|
try {
|
|
pid = Std.parseInt(k.split("-")[1].substr(1));
|
|
did = Std.parseInt(k.split("-")[0].substr(1));
|
|
} catch (e:Dynamic) {
|
|
trace("unable to parse key " + k);
|
|
}
|
|
|
|
// find related element in userOrders
|
|
var uo = null;
|
|
for (x in userOrders) {
|
|
if (x.distrib != null && x.distrib.id != did) {
|
|
continue;
|
|
} else {
|
|
for (a in x.datas) {
|
|
if (a.product.id == pid) {
|
|
uo = a;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uo == null)
|
|
throw t._("Could not find the product ::produ:: and delivery ::deliv::", {produ: pid, deliv: did});
|
|
|
|
var q = 0.0;
|
|
|
|
if (uo.product.hasFloatQt) {
|
|
var param = StringTools.replace(qt, ",", ".");
|
|
q = Std.parseFloat(param);
|
|
} else {
|
|
q = Std.parseInt(qt);
|
|
}
|
|
|
|
if (uo.order != null) {
|
|
OrderService.edit(uo.order, q);
|
|
} else {
|
|
OrderService.make(app.user, q, uo.product, did);
|
|
}
|
|
}
|
|
throw Ok("/contract/order/" + c.id, t._("Your order has been updated"));
|
|
}
|
|
|
|
view.c = view.contract = c;
|
|
view.userOrders = userOrders;
|
|
}
|
|
|
|
/**
|
|
* Make an order by contract ( standard mode ) + payment process
|
|
*/
|
|
@tpl("contract/orderAndPay.mtt")
|
|
function doOrderAndPay(c:db.Contract) {
|
|
// checks
|
|
if (!app.user.amap.hasPayments())
|
|
throw Redirect("/contract/order/" + c.id);
|
|
if (app.user.amap.hasShopMode())
|
|
throw Redirect("/");
|
|
if (!c.isUserOrderAvailable())
|
|
throw Error("/", t._("This contract is not opened for orders"));
|
|
|
|
var distributions = [];
|
|
/* If its a varying contract, we display a column by distribution*/
|
|
if (c.type == db.Contract.TYPE_VARORDER) {
|
|
distributions = db.Distribution.getOpenToOrdersDeliveries(c);
|
|
}
|
|
|
|
// list of distribs with a list of product and optionnaly an order
|
|
var userOrders = new Array<{distrib:db.Distribution, datas:Array<{order:db.UserContract, product:db.Product}>}>();
|
|
var products = c.getProducts();
|
|
|
|
for (d in distributions) {
|
|
var datas = [];
|
|
for (p in products) {
|
|
var ua = {order: null, product: p};
|
|
|
|
var order:db.UserContract = null;
|
|
if (c.type == db.Contract.TYPE_VARORDER) {
|
|
order = db.UserContract.manager.select($user == app.user && $productId == p.id && $distributionId == d.id, true);
|
|
} else {
|
|
order = db.UserContract.manager.select($user == app.user && $productId == p.id, true);
|
|
}
|
|
|
|
if (order != null)
|
|
ua.order = order;
|
|
datas.push(ua);
|
|
}
|
|
|
|
userOrders.push({distrib: d, datas: datas});
|
|
}
|
|
|
|
// form check
|
|
if (checkToken()) {
|
|
// get distrib if needed
|
|
var distrib = null;
|
|
if (c.type == db.Contract.TYPE_VARORDER) {
|
|
distrib = db.Distribution.manager.get(Std.parseInt(app.params.get("distribution")), false);
|
|
}
|
|
|
|
var orders:OrderInSession = {products: [], userId: app.user.id, total: 0};
|
|
|
|
for (k in app.params.keys()) {
|
|
if (k.substr(0, 1) != "d")
|
|
continue;
|
|
var qt = app.params.get(k);
|
|
if (qt == "")
|
|
continue;
|
|
|
|
var pid = null;
|
|
var did = null;
|
|
try {
|
|
pid = Std.parseInt(k.split("-")[1].substr(1));
|
|
did = Std.parseInt(k.split("-")[0].substr(1));
|
|
} catch (e:Dynamic) {
|
|
trace("unable to parse key " + k);
|
|
}
|
|
|
|
// find related element in userOrders
|
|
var uo = null;
|
|
for (x in userOrders) {
|
|
if (x.distrib != null && x.distrib.id != did) {
|
|
continue;
|
|
} else {
|
|
for (a in x.datas) {
|
|
if (a.product.id == pid) {
|
|
uo = a;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uo == null)
|
|
throw t._("Could not find the product ::produ:: and delivery ::deliv::", {produ: pid, deliv: did});
|
|
|
|
// quantity
|
|
var q = 0.0;
|
|
if (uo.product.hasFloatQt) {
|
|
var param = StringTools.replace(qt, ",", ".");
|
|
q = Std.parseFloat(param);
|
|
} else {
|
|
q = Std.parseInt(qt);
|
|
}
|
|
|
|
orders.products.push({productId: pid, quantity: q, distributionId: did});
|
|
|
|
var p = db.Product.manager.get(pid, false);
|
|
orders.total += p.getPrice() * q;
|
|
}
|
|
|
|
App.current.session.data.order = orders;
|
|
|
|
// Go to payments page
|
|
if (c.type == db.Contract.TYPE_CONSTORDERS) {
|
|
throw Ok("/contract/order/" + c.id, t._("Your CSA order has been saved"));
|
|
} else {
|
|
throw Ok("/transaction/pay/", t._("In order to save your order, please choose a means of payment."));
|
|
}
|
|
}
|
|
|
|
view.c = view.contract = c;
|
|
view.userOrders = userOrders;
|
|
}
|
|
|
|
/**
|
|
* A user edit an order for a multidistrib.
|
|
*/
|
|
@tpl("contract/orderByDate.mtt")
|
|
function doEditOrderByDate(date:Date) {
|
|
if (app.user.amap.hasPayments()) {
|
|
// when payments are active, the user cannot modify his order
|
|
throw Redirect("/");
|
|
}
|
|
|
|
// cannot edit order if date is in the past
|
|
if (Date.now().getTime() > date.getTime()) {
|
|
var msg = t._("This delivery has already taken place, you can no longer modify the order.");
|
|
if (app.user.isContractManager())
|
|
msg += t._("<br/>As the manager of the contract you can modify the order from this page: <a href='/contractAdmin'>Management of contracts</a>");
|
|
|
|
throw Error("/contract", msg);
|
|
}
|
|
|
|
// Il faut regarder le contrat de chaque produit et verifier si le contrat est toujours ouvert à la commande.
|
|
var d1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
|
|
var d2 = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
|
|
|
|
var cids = Lambda.map(app.user.amap.getActiveContracts(true), function(c) return c.id);
|
|
var distribs = db.Distribution.manager.search(($contractId in cids) && $date >= d1 && $date <= d2, false);
|
|
var orders = db.UserContract.manager.search($userId == app.user.id
|
|
&& $distributionId in Lambda.map(distribs, function(d) return d.id));
|
|
view.orders = service.OrderService.prepare(orders);
|
|
view.date = date;
|
|
|
|
// form check
|
|
if (checkToken()) {
|
|
var orders_out = [];
|
|
|
|
for (k in app.params.keys()) {
|
|
var param = app.params.get(k);
|
|
if (k.substr(0, "product".length) == "product") {
|
|
// trouve le produit dans userOrders
|
|
var pid = Std.parseInt(k.substr("product".length));
|
|
var order = Lambda.find(orders, function(uo) return uo.product.id == pid);
|
|
if (order == null)
|
|
throw t._("Error, could not find the order");
|
|
|
|
var q = 0.0;
|
|
if (order.product.hasFloatQt) {
|
|
param = StringTools.replace(param, ",", ".");
|
|
q = Std.parseFloat(param);
|
|
} else {
|
|
q = Std.parseInt(param);
|
|
}
|
|
|
|
var quantity = Math.abs(q == null ? 0 : q);
|
|
|
|
if (order.distribution.canOrderNow()) {
|
|
// met a jour la commande
|
|
var o = OrderService.edit(order, quantity);
|
|
if (o != null)
|
|
orders_out.push(o);
|
|
}
|
|
}
|
|
}
|
|
|
|
app.event(MakeOrder(orders_out));
|
|
|
|
throw Ok("/contract", t._("Your order has been updated"));
|
|
}
|
|
}
|
|
}
|