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.

384 lines
10 KiB

  1. package;
  2. import Common;
  3. using tools.ObjectListTool;
  4. using Lambda;
  5. using tools.ObjectListTool;
  6. /**
  7. * MultiDistrib represents many db.Distribution
  8. which happen on the same day + same place.
  9. *
  10. * @author fbarbut
  11. */
  12. class MultiDistrib
  13. {
  14. public var distributions : Array<db.Distribution>;
  15. public var contracts : Array<db.Contract>;
  16. //public var actions : Array<Link>;
  17. public var extraHtml : String;
  18. public var type : Null<Int>; //contract type, both contract types cannot be mixed in a same multidistrib.
  19. public function new(){
  20. distributions = [];
  21. contracts = [];
  22. extraHtml = "";
  23. //actions = [];
  24. }
  25. public static function get(date:Date, place:db.Place,contractType:Int){
  26. var m = new MultiDistrib();
  27. var start = tools.DateTool.setHourMinute(date, 0, 0);
  28. var end = tools.DateTool.setHourMinute(date, 23, 59);
  29. var contracts = place.amap.getContracts().array();
  30. //filter by type
  31. if(contractType==db.Contract.TYPE_VARORDER){
  32. for(c in contracts.copy() ){
  33. if(c.type!=db.Contract.TYPE_VARORDER) contracts.remove(c);
  34. }
  35. }else if(contractType==db.Contract.TYPE_CONSTORDERS){
  36. for(c in contracts.copy() ){
  37. if(c.type!=db.Contract.TYPE_CONSTORDERS) contracts.remove(c);
  38. }
  39. }
  40. var cids = contracts.getIds();
  41. m.distributions = db.Distribution.manager.search(($contractId in cids) && ($date >= start) && ($date <= end) && $place==place, { orderBy:date }, false).array();
  42. m.type = contractType;
  43. return m;
  44. }
  45. /**
  46. Get multidistribs from a time range + place + type
  47. **/
  48. public static function getFromTimeRange(group:db.Amap,from:Date,to:Date,?contractType:Int):Array<MultiDistrib>{
  49. var multidistribs = [];
  50. var start = tools.DateTool.setHourMinute(from, 0, 0);
  51. var end = tools.DateTool.setHourMinute(to, 23, 59);
  52. var cids = group.getContracts().getIds();
  53. var distributions = db.Distribution.manager.search(($contractId in cids) && ($date >= start) && ($date <= end) , { orderBy:date }, false).array();
  54. //sort by day-place-type
  55. var multidistribs = new Map<String,MultiDistrib>();
  56. for ( d in distributions){
  57. //filter by contractType
  58. if(contractType!=null){
  59. if(d.contract.type!=contractType) continue;
  60. }
  61. var key = d.getKey() + "-" + d.contract.type;
  62. if(multidistribs[key]==null){
  63. var m = new MultiDistrib();
  64. m.distributions.push(d);
  65. m.type = d.contract.type;
  66. multidistribs[key] = m;
  67. }else{
  68. multidistribs[key].distributions.push(d);
  69. }
  70. }
  71. var multidistribs = Lambda.array(multidistribs);
  72. //trigger event
  73. for(md in multidistribs) App.current.event(MultiDistribEvent(md));
  74. //sort by date desc
  75. multidistribs.sort(function(x,y){
  76. return Math.round( x.getDate().getTime()/1000 ) - Math.round(y.getDate().getTime()/1000 );
  77. });
  78. return multidistribs;
  79. }
  80. /**
  81. * TODO : refacto this to use getFromTimeRange();
  82. */
  83. /*public static function getNextMultiDeliveries(group:db.Amap){
  84. var out = new Map < String, {
  85. place:db.Place, //common delivery place
  86. startDate:Date, //global delivery start
  87. endDate:Date, //global delivery stop
  88. orderStartDate:Date, //global orders opening date
  89. orderEndDate:Date, //global orders closing date
  90. active:Bool,
  91. products:Array<ProductInfo>, //available products ( if no order )
  92. myOrders:Array<{distrib:db.Distribution,orders:Array<UserOrder>}> //my orders
  93. }>();
  94. var n = Date.now();
  95. var now = new Date(n.getFullYear(), n.getMonth(), n.getDate(), 0, 0, 0);
  96. var contracts = db.Contract.getActiveContracts(group);
  97. var cids = Lambda.map(contracts, function(p) return p.id);
  98. //var pids = Lambda.map(db.Product.manager.search($contractId in cids,false), function(x) return x.id);
  99. //var out = UserContract.manager.search(($userId == id || $userId2 == id) && $productId in pids, lock);
  100. //available deliveries
  101. var inSixMonth = DateTools.delta(now, 1000.0 * 60 * 60 * 24 * 30 * 6);
  102. var distribs = db.Distribution.manager.search(($contractId in cids) && $date >= now && $date <= inSixMonth , { orderBy:date }, false);
  103. for (d in distribs) {
  104. //we had the distribution key ( place+date ) and the contract type in order to separate constant and varying contracts
  105. var key = d.getKey() + "|" + d.contract.type;
  106. var o = out.get(key);
  107. if (o == null) o = {place:d.place, startDate:d.date, active:null, endDate:d.end, products:[], myOrders:[], orderStartDate:null,orderEndDate:null};
  108. //user orders
  109. var orders = [];
  110. if(App.current.user!=null) orders = d.contract.getUserOrders(App.current.user,d);
  111. if (orders.length > 0){
  112. o.myOrders.push({distrib:d,orders:service.OrderService.prepare(orders)});
  113. }else{
  114. //no "order block" if no shop mode
  115. if (!group.hasShopMode() ) {
  116. continue;
  117. }
  118. //if its a constant order contract, skip this delivery
  119. if (d.contract.type == db.Contract.TYPE_CONSTORDERS){
  120. continue;
  121. }
  122. //products preview if no orders
  123. for ( p in d.contract.getProductsPreview(9)){
  124. o.products.push( p.infos(null,false) );
  125. }
  126. }
  127. if (d.contract.type == db.Contract.TYPE_VARORDER){
  128. //old distribs may have an empty orderStartDate
  129. if (d.orderStartDate == null) {
  130. continue;
  131. }
  132. //if order opening is more far than 1 month, skip it
  133. // if (d.orderStartDate.getTime() > inOneMonth.getTime() ){
  134. // continue;
  135. // }
  136. //display closest opening date
  137. if (o.orderStartDate == null){
  138. o.orderStartDate = d.orderStartDate;
  139. }else if (o.orderStartDate.getTime() > d.orderStartDate.getTime()){
  140. o.orderStartDate = d.orderStartDate;
  141. }
  142. //display most far closing date
  143. if (o.orderEndDate == null){
  144. o.orderEndDate = d.orderEndDate;
  145. }else if (o.orderEndDate.getTime() < d.orderEndDate.getTime()){
  146. o.orderEndDate = d.orderEndDate;
  147. }
  148. out.set(key, o);
  149. }else{
  150. //in constant orders, add block only if there is an order
  151. if(o.myOrders.length>0) out.set(key, o);
  152. }
  153. }
  154. //shuffle and limit product lists
  155. for ( o in out){
  156. o.products = thx.Arrays.shuffle(o.products);
  157. o.products = o.products.slice(0, 9);
  158. }
  159. //decide if active or not
  160. var now = Date.now();
  161. for( o in out){
  162. if (o.orderStartDate == null) continue; //constant orders
  163. if (now.getTime() >= o.orderStartDate.getTime() && now.getTime() <= o.orderEndDate.getTime() ){
  164. //order currently open
  165. o.active = true;
  166. }else {
  167. o.active = false;
  168. }
  169. }
  170. return Lambda.array(out);
  171. }*/
  172. public function getPlace(){
  173. if(distributions.length==0) throw "This multidistrib is empty";
  174. return distributions[0].place;
  175. }
  176. public function getDate(){
  177. if(distributions.length==0) throw "This multidistrib is empty";
  178. return distributions[0].date;
  179. }
  180. public function getEndDate(){
  181. if(distributions.length==0) throw "This multidistrib is empty";
  182. return distributions[0].end;
  183. }
  184. public function getProductsExcerpt():Array<ProductInfo>{
  185. var key = "productsExcerpt-"+getKey();
  186. var cache:Array<Int> = sugoi.db.Cache.get(key);
  187. if(cache!=null){
  188. var out = [];
  189. //try{
  190. for( pid in cache.array()){
  191. var p = db.Product.manager.get(pid,false);
  192. if(p!=null) out.push(p.infos());
  193. }
  194. //}catch(e:Dynamic){
  195. // sugoi.db.Cache.destroy(key);
  196. // }
  197. return out;
  198. }
  199. var products = [];
  200. for( d in distributions){
  201. for ( p in d.contract.getProductsPreview(9)){
  202. products.push( p.infos(null,false) );
  203. }
  204. }
  205. products = thx.Arrays.shuffle(products);
  206. products = products.slice(0, 9);
  207. sugoi.db.Cache.set(key, products.map(function(p)return p.id).array(), 3600 );
  208. return products;
  209. }
  210. public function userHasOrders(user:db.User):Bool{
  211. if(user==null) return false;
  212. for ( d in distributions){
  213. if(d.getUserOrders(user).length>0) return true;
  214. }
  215. return false;
  216. }
  217. /**
  218. orders currently open ?
  219. **/
  220. public function isActive(){
  221. if (getOrdersStartDate() == null) return false; //constant orders
  222. var now = Date.now();
  223. if (now.getTime() >= getOrdersStartDate().getTime() && now.getTime() <= getOrdersEndDate().getTime() ){
  224. return true;
  225. }else {
  226. return false;
  227. }
  228. }
  229. public function getOrdersStartDate(){
  230. var date = null;
  231. for( d in distributions ){
  232. if(d.orderStartDate==null) continue;
  233. //display closest opening date
  234. if (date == null){
  235. date = d.orderStartDate;
  236. }else if (date.getTime() > d.orderStartDate.getTime()){
  237. date = d.orderStartDate;
  238. }
  239. }
  240. return date;
  241. }
  242. /*public function hasOnlyConstantOrders(){
  243. for(d in distributions){
  244. if( d.contract.type==db.Contract.TYPE_VARORDER ) {
  245. return false;
  246. }
  247. }
  248. return true;
  249. }*/
  250. public function getOrdersEndDate(){
  251. var date = null;
  252. for( d in distributions ){
  253. if(d.orderEndDate==null) continue;
  254. //display most far closing date
  255. if (date == null){
  256. date = d.orderEndDate;
  257. }else if (date.getTime() < d.orderEndDate.getTime()){
  258. date = d.orderEndDate;
  259. }
  260. }
  261. return date;
  262. }
  263. /**
  264. * Get all orders involved in this multidistrib
  265. */
  266. public function getOrders(){
  267. var out = [];
  268. for ( d in distributions){
  269. out = out.concat(d.getOrders().array());
  270. }
  271. return out;
  272. }
  273. /**
  274. * Get orders for a user in this multidistrib
  275. * @param user
  276. */
  277. public function getUserOrders(user:db.User){
  278. var out = [];
  279. for ( d in distributions){
  280. var pids = Lambda.map( d.contract.getProducts(false), function(x) return x.id);
  281. var userOrders = db.UserContract.manager.search( $userId == user.id && $distributionId==d.id && $productId in pids , false);
  282. for( o in userOrders ){
  283. out.push(o);
  284. }
  285. }
  286. return out;
  287. }
  288. public function getUsers(){
  289. var users = [];
  290. for ( o in getOrders()) users.push(o.user);
  291. return users.deduplicate();
  292. }
  293. public function isConfirmed():Bool{
  294. //cannot be in future
  295. if(getDate().getTime()>Date.now().getTime()) return false;
  296. return Lambda.count( distributions, function(d) return d.validated) == distributions.length;
  297. }
  298. public function checkConfirmed():Bool{
  299. var orders = getOrders();
  300. var c = Lambda.count( orders, function(d) return d.paid) == orders.length;
  301. if (c){
  302. for ( d in distributions){
  303. if (!d.validated){
  304. d.lock();
  305. d.validated = true;
  306. d.update();
  307. }
  308. }
  309. }
  310. return c;
  311. }
  312. //get key by date-place-type
  313. public function getKey(){
  314. return distributions[0].getKey() + "-" + distributions[0].contract.type;
  315. }
  316. }