Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

742 lines
27KB

  1. var app = new Vue({
  2. el: '#app-order-order',
  3. data() {
  4. return Object.assign({
  5. order: null,
  6. loading: false,
  7. loadingInit: true,
  8. step: null,
  9. producer: null,
  10. user: null,
  11. date: null,
  12. dateFormat: null,
  13. distributions: [],
  14. distribution: null,
  15. pointsSale: [],
  16. pointSaleActive: null,
  17. pointSaleActiveId: null,
  18. pointsSaleCodes: [],
  19. products: [],
  20. categories: [],
  21. categoryCurrent: null,
  22. comment: '',
  23. creditCheckbox: false,
  24. useCredit: false,
  25. errors: [],
  26. disableConfirmButton: false,
  27. delivery: false,
  28. deliveryAddress: null,
  29. urlLogin: '#',
  30. producerOptionOrderEntryPoint: null,
  31. calendar: {
  32. columns: this.isMobile() ? 1 : 2,
  33. mode: 'single',
  34. attrs: [],
  35. availableDates: [],
  36. themeStyles: {
  37. wrapper: {
  38. background: '#F7F7F7',
  39. color: '#333',
  40. border: 'solid 1px #e0e0e0'
  41. },
  42. header: {
  43. padding: '10px 10px',
  44. },
  45. headerHorizontalDivider: {
  46. borderTop: 'solid rgba(255, 255, 255, 0.2) 1px',
  47. width: '80%',
  48. },
  49. weekdays: {
  50. color: 'gray',
  51. fontWeight: '600',
  52. padding: '10px 10px',
  53. fontSize: '2rem'
  54. },
  55. weeks: {
  56. padding: '0 15px 15px 15px',
  57. },
  58. dayContent: function (object) {
  59. var style = {
  60. fontSize: '1.4rem',
  61. padding: app.isMobile() ? '18px' : '20px',
  62. };
  63. return style;
  64. },
  65. },
  66. formats: {
  67. dayPopover: 'DD/MM/YYYY'
  68. }
  69. }
  70. }, window.appInitValues);
  71. },
  72. mounted: function() {
  73. this.initDate();
  74. this.init('first');
  75. },
  76. methods: {
  77. initDate: function() {
  78. var dateDefined = $('#order-distribution-date').size() || $('#distribution-date').size() ;
  79. if(dateDefined && (this.producerOptionOrderEntryPoint != 'point-sale' || this.pointSaleActiveId)) {
  80. if($('#order-distribution-date').size()) {
  81. this.date = new Date($('#order-distribution-date').html()) ;
  82. }
  83. else {
  84. this.date = new Date($('#distribution-date').html()) ;
  85. }
  86. this.dateFormat = ('0' + this.date.getDate()).slice(-2)+ '/'
  87. + ('0' + (this.date.getMonth() +1)).slice(-2) + '/'
  88. + this.date.getFullYear() ;
  89. }
  90. },
  91. getDate: function() {
  92. return this.formatDate(this.date) ;
  93. },
  94. formatDate: function(date) {
  95. if(date) {
  96. return date.getFullYear() + '-'
  97. + ('0' + (date.getMonth() +1)).slice(-2) + '-'
  98. + ('0' + date.getDate()).slice(-2) ;
  99. }
  100. return false ;
  101. },
  102. formatPrice: formatPrice,
  103. getPointSale: function(idPointSale) {
  104. for(var key in this.pointsSale) {
  105. if(this.pointsSale[key].id == idPointSale) {
  106. return this.pointsSale[key] ;
  107. }
  108. }
  109. },
  110. getPointSaleKey: function(idPointSale) {
  111. for(var key in this.pointsSale) {
  112. if(this.pointsSale[key].id == idPointSale) {
  113. return key ;
  114. }
  115. }
  116. },
  117. getProduct: function(idProduct) {
  118. for(var key in this.products) {
  119. if(this.products[key].id == idProduct) {
  120. return this.products[key] ;
  121. }
  122. }
  123. },
  124. init: function(type, oldStep, step) {
  125. var app = this ;
  126. this.loading = true ;
  127. if(app.isChangeState('date', 'date', 'point-sale')) {
  128. app.pointSaleActive = null ;
  129. app.products = [] ;
  130. }
  131. axios.get("ajax-infos",{params: {
  132. date : this.getDate(),
  133. pointSaleId: this.pointSaleActiveId ? this.pointSaleActiveId : (this.pointSaleActive ? this.pointSaleActive.id : 0)
  134. }})
  135. .then(function(response) {
  136. app.calendar.attrs = [];
  137. app.calendar.availableDates = [];
  138. var distributions = response.data.distributions;
  139. if (distributions.length) {
  140. app.distributions = distributions;
  141. var arrayDate;
  142. for (var i = 0; i < distributions.length; i++) {
  143. app.calendar.attrs.push({
  144. highlight: true,
  145. dates: distributions[i].date
  146. });
  147. arrayDate = distributions[i].date.split('-');
  148. app.calendar.availableDates.push({
  149. start: new Date(arrayDate[0], arrayDate[1] - 1, arrayDate[2]),
  150. end: new Date(arrayDate[0], arrayDate[1] - 1, arrayDate[2])
  151. });
  152. }
  153. }
  154. if (response.data.distribution) {
  155. app.distribution = response.data.distribution;
  156. }
  157. var orders = [];
  158. if (response.data.orders) {
  159. orders = response.data.orders;
  160. }
  161. if (orders.length) {
  162. for (var i = 0; i < orders.length; i++) {
  163. arrayDate = orders[i].date_distribution.split('-');
  164. var dateOrder = new Date(arrayDate[0], arrayDate[1] - 1, arrayDate[2]);
  165. if (app.isAvailableDate(dateOrder)) {
  166. app.calendar.attrs.push({
  167. highlight: true,
  168. popover: {
  169. label: orders[i].pointSale.name + ' / ' + app.formatPrice(orders[i].amount_total),
  170. hideIndicator: true
  171. },
  172. dates: orders[i].date_distribution
  173. });
  174. }
  175. }
  176. }
  177. app.producer = response.data.producer;
  178. app.user = response.data.user;
  179. app.useCredit = response.data.producer.use_credit_checked_default;
  180. if (response.data.points_sale) {
  181. app.pointsSale = [];
  182. var orderPointSale = 0;
  183. for (var key in response.data.points_sale) {
  184. response.data.points_sale[key].order = orderPointSale++;
  185. app.pointsSale[response.data.points_sale[key].id] = response.data.points_sale[key];
  186. if(!app.pointsSaleCodes[response.data.points_sale[key].id]) {
  187. app.pointsSaleCodes[response.data.points_sale[key].id] = '';
  188. Vue.set(app.pointsSaleCodes, response.data.points_sale[key].id, '');
  189. }
  190. }
  191. }
  192. if(app.pointSaleActiveId) {
  193. app.pointSaleActive = app.getPointSale(app.pointSaleActiveId);
  194. }
  195. if(app.isChangeState('point-sale', 'point-sale', 'date')) {
  196. app.date = null ;
  197. app.dateFormat = null ;
  198. }
  199. // update order
  200. var updateOrder = false ;
  201. if(app.isChangeState('date', 'point-sale', 'products')
  202. || app.isChangeState('date', 'date', 'point-sale')
  203. || app.isChangeState('point-sale', 'date', 'products')
  204. || app.isChangeState('point-sale', 'point-sale', 'date')) {
  205. updateOrder = true ;
  206. }
  207. if(updateOrder) {
  208. app.updateOrder(response);
  209. }
  210. if(type == 'first') {
  211. if(app.getDate() && app.pointSaleActive) {
  212. app.step = 'products' ;
  213. if(response.data.products) {
  214. app.products = response.data.products;
  215. }
  216. app.updateOrder(response);
  217. }
  218. else if(app.producer.option_order_entry_point == 'point-sale') {
  219. app.step = 'point-sale' ;
  220. }
  221. else if(app.getDate() && app.producer && app.producer.option_order_entry_point == 'date') {
  222. app.step = 'point-sale' ;
  223. }
  224. else {
  225. app.step = 'date' ;
  226. }
  227. }
  228. if(response.data.categories) {
  229. app.categories = response.data.categories ;
  230. for(keyCategory in response.data.categories) {
  231. var category = response.data.categories[keyCategory];
  232. if(category.id && app.countProductsByCategory(category)) {
  233. app.setCategoryCurrent(category, true) ;
  234. break;
  235. }
  236. }
  237. }
  238. setTimeout(function() {
  239. app.responsive();
  240. opendistrib_products();
  241. }, 500);
  242. app.loading = false ;
  243. app.loadingInit = false ;
  244. });
  245. },
  246. updateOrder: function(response) {
  247. var app = this;
  248. if(response.data.products) {
  249. app.products = response.data.products;
  250. }
  251. app.order = null ;
  252. if(response.data.order) {
  253. app.order = response.data.order ;
  254. app.comment = app.order.comment ;
  255. if(app.order.delivery_address && app.order.delivery_address.length > 0) {
  256. app.deliveryAddress = app.order.delivery_address ;
  257. }
  258. app.pointSaleActive = app.getPointSale(response.data.order.id_point_sale) ;
  259. }
  260. else {
  261. app.comment = null ;
  262. app.deliveryAddress = null ;
  263. if(app.user.address && app.user.address.length > 0) {
  264. app.deliveryAddress = app.user.address ;
  265. }
  266. }
  267. },
  268. isMobile: function() {
  269. var width_window = parseInt($(window).width());
  270. return width_window <= 768;
  271. },
  272. responsive: function() {
  273. var app = this;
  274. app.responsiveApply();
  275. $(window).resize(function() {
  276. app.responsiveApply();
  277. });
  278. },
  279. responsiveApply: function() {
  280. var $td_summary = $('#products tr.total td.summary');
  281. if(this.isMobile()) {
  282. $td_summary.attr('colspan', 3);
  283. }
  284. else {
  285. $td_summary.attr('colspan', 4);
  286. }
  287. },
  288. isChangeState: function(entryPoint, oldStep, newStep) {
  289. return this.producer
  290. && entryPoint == this.producer.option_order_entry_point
  291. && oldStep == this.oldStep
  292. && newStep == this.step ;
  293. },
  294. nextStep: function() {
  295. this.errors = [] ;
  296. var oldStep = this.step ;
  297. var nextStep = null ;
  298. // par point de vente
  299. if(this.producer && this.producer.option_order_entry_point == 'point-sale') {
  300. if(oldStep == 'point-sale') {
  301. nextStep = 'date' ;
  302. }
  303. else if(oldStep == 'date') {
  304. nextStep = 'products' ;
  305. }
  306. }
  307. // par date
  308. else {
  309. if(oldStep == 'date') {
  310. nextStep = 'point-sale' ;
  311. }
  312. else if(oldStep == 'point-sale') {
  313. nextStep = 'products' ;
  314. }
  315. }
  316. if(nextStep) {
  317. this.changeStep(nextStep) ;
  318. }
  319. },
  320. changeStep: function(step) {
  321. this.errors = [] ;
  322. var oldStep = this.step ;
  323. this.oldStep = oldStep ;
  324. if(oldStep == 'products' && step == 'payment') {
  325. this.checkProducts() ;
  326. }
  327. if(!this.errors.length) {
  328. this.step = step ;
  329. window.scroll(0, $('#page-title').position().top - 25) ;
  330. this.init('basic', oldStep, step) ;
  331. }
  332. },
  333. dayClickList: function(event) {
  334. var dateStr = event.currentTarget.getAttribute('data-distribution-date') ;
  335. var dateObject = new Date(dateStr.replace(/-/g, "/")) ;
  336. if(this.isAvailableDate(dateObject)) {
  337. this.dayClickEvent(dateObject) ;
  338. }
  339. },
  340. dayClick: function(day) {
  341. if(this.isAvailableDate(day.date)) {
  342. this.dayClickEvent(day.date) ;
  343. }
  344. },
  345. dayClickEvent: function(date) {
  346. this.date = date ;
  347. this.dateFormat = ('0' + this.date.getDate()).slice(-2)+ '/'
  348. + ('0' + (this.date.getMonth() +1)).slice(-2) + '/'
  349. + this.date.getFullYear() ;
  350. this.nextStep() ;
  351. },
  352. isAvailableDate: function(date) {
  353. for(var key in this.calendar.availableDates) {
  354. if(date.getTime() == this.calendar.availableDates[key].start.getTime()) {
  355. return true ;
  356. }
  357. }
  358. return false ;
  359. },
  360. pointSaleClick: function(event) {
  361. var app = this ;
  362. var idPointSale = event.currentTarget.getAttribute('data-id-point-sale') ;
  363. var hasCode = event.currentTarget.getAttribute('data-code') ;
  364. if(hasCode) {
  365. axios.get('ajax-validate-code-point-sale',{params: {
  366. idPointSale: idPointSale,
  367. code: this.pointsSaleCodes[idPointSale]
  368. }}).then(function(response) {
  369. if(response.data) {
  370. app.pointsSale[app.getPointSaleKey(idPointSale)].invalid_code = false ;
  371. app.validatePointSale(idPointSale) ;
  372. }
  373. else {
  374. app.pointsSale[app.getPointSaleKey(idPointSale)].invalid_code = true ;
  375. Vue.set(app.pointsSaleCodes, idPointSale, '');
  376. }
  377. }) ;
  378. }
  379. else {
  380. this.validatePointSale(idPointSale) ;
  381. }
  382. },
  383. validatePointSale: function(idPointSale) {
  384. this.pointSaleActive = this.getPointSale(idPointSale) ;
  385. if(this.pointSaleActive.credit_functioning == 'mandatory' || (this.pointSaleActive.credit_functioning == 'user' && this.user.credit_active)) {
  386. this.useCredit = true ;
  387. }
  388. this.nextStep() ;
  389. },
  390. productQuantityClick: function(product, quantity) {
  391. if( this.products[product.index].quantity_form + quantity >= 0 &&
  392. (this.products[product.index].quantity_form + quantity <= (this.products[product.index].quantity_remaining * this.products[product.index].coefficient_unit) ||
  393. !this.products[product.index].quantity_max)
  394. ) {
  395. var theQuantity = parseFloat(this.products[product.index].quantity_form) + parseFloat(quantity);
  396. this.products[product.index].quantity_form = parseFloat(theQuantity.toFixed(2)) ;
  397. }
  398. },
  399. oneProductOrdered: function() {
  400. for(var key in this.products) {
  401. if(this.products[key].quantity_form > 0) {
  402. return true ;
  403. }
  404. }
  405. return false ;
  406. },
  407. countProductOrdered: function() {
  408. var count = 0 ;
  409. for(var key in this.products) {
  410. if(this.products[key].quantity_form > 0) {
  411. if(this.products[key].unit != 'piece') {
  412. count ++ ;
  413. }
  414. else {
  415. count += this.products[key].quantity_form ;
  416. }
  417. }
  418. }
  419. return count ;
  420. },
  421. priceTotal: function(format) {
  422. var price = 0 ;
  423. for(var key in this.products) {
  424. var quantity = this.products[key].quantity_form;
  425. if(quantity > 0) {
  426. price += (quantity / this.products[key].unit_coefficient) * this.getBestProductPrice(this.products[key].id, this.products[key].quantity_form);
  427. }
  428. }
  429. if(format) {
  430. return this.formatPrice(price) ;
  431. }
  432. else {
  433. return numberDecimals(price, 2) ;
  434. }
  435. },
  436. productHasPrice: function(product) {
  437. return product.prices && product.prices.length > 0;
  438. },
  439. productHasPriceWithFromQuantity: function(product) {
  440. if(this.productHasPrice(product)) {
  441. for(var i = 0; i < product.prices.length; i++) {
  442. if(product.prices[i].from_quantity > 0) {
  443. return true;
  444. }
  445. }
  446. }
  447. return false;
  448. },
  449. getBestProductPrice: function(idProduct, theQuantity) {
  450. var thePriceWithTax = 9999;
  451. var product = this.getProduct(idProduct);
  452. var pricesArray = product.prices;
  453. var unitCoefficient = product.unit_coefficient;
  454. if(theQuantity) {
  455. theQuantity = theQuantity / unitCoefficient;
  456. }
  457. for(var i = 0; i < pricesArray.length ; i++) {
  458. var priceWithTax = pricesArray[i].price_with_tax;
  459. var fromQuantity = pricesArray[i].from_quantity;
  460. if(priceWithTax < thePriceWithTax && fromQuantity <= theQuantity) {
  461. thePriceWithTax = priceWithTax;
  462. }
  463. }
  464. if(thePriceWithTax == 9999) {
  465. return 0;
  466. }
  467. else {
  468. return thePriceWithTax;
  469. }
  470. },
  471. confirmClick: function() {
  472. var app = this ;
  473. // delivery
  474. if(app.pointSaleActive.is_home_delivery && !app.deliveryAddress) {
  475. this.errors = [] ;
  476. this.errors.push('Veuillez saisir une adresse de livraison.') ;
  477. opendistrib_scroll('page-title');
  478. return false ;
  479. }
  480. // montant minimum de commande
  481. if(app.pointSaleActive.minimum_order_amount > 0 && app.priceTotal() < app.pointSaleActive.minimum_order_amount) {
  482. this.errors = [] ;
  483. this.errors.push('Le montant minimum de commande est de '+app.formatPrice(app.pointSaleActive.minimum_order_amount)+' pour ce point de vente.') ;
  484. opendistrib_scroll('page-title');
  485. return false ;
  486. }
  487. // guest form
  488. var $signupGuestForm = $('#signup-guest form') ;
  489. if($signupGuestForm.length > 0 && !$signupGuestForm.valid()) {
  490. $signupGuestForm.submit() ;
  491. return false ;
  492. }
  493. var user = false ;
  494. if(this.producer.option_allow_order_guest && !this.user) {
  495. user = {
  496. email: $('#signupguest-email').val(),
  497. password: $('#signupguest-password').val(),
  498. firstname: $('#signupguest-firstname').val(),
  499. lastname: $('#signupguest-lastname').val(),
  500. phone: $('#signupguest-phone').val(),
  501. } ;
  502. }
  503. // products
  504. var productsArray = {} ;
  505. for(var key in this.products) {
  506. if( this.products[key].quantity_form != null &&
  507. this.products[key].quantity_form > 0) {
  508. productsArray[this.products[key].id] = this.products[key].quantity_form ;
  509. }
  510. }
  511. app.disableConfirmButton = true ;
  512. axios.post('ajax-process', {
  513. Order: {
  514. id_distribution : this.distribution.id,
  515. id_point_sale: this.pointSaleActive.id,
  516. comment: this.comment,
  517. delivery_home: this.pointSaleActive.is_home_delivery,
  518. delivery_address: this.deliveryAddress
  519. },
  520. code_point_sale: this.pointsSaleCodes[this.pointSaleActive.id],
  521. products: productsArray,
  522. use_credit: Number(this.useCredit),
  523. user: user
  524. }).then(function(response) {
  525. if(response.data.status == 'success') {
  526. app.errors = [] ;
  527. if(response.data.redirect && response.data.redirect.length > 0) {
  528. window.location.href = response.data.redirect ;
  529. }
  530. else {
  531. window.location.href = opendistrib_base_url(true)+'order/confirm?idOrder='+response.data.idOrder ;
  532. }
  533. }
  534. else {
  535. app.errors = response.data.errors ;
  536. app.disableConfirmButton = false ;
  537. }
  538. });
  539. },
  540. checkProducts: function() {
  541. if(!this.oneProductOrdered()) {
  542. this.errors.push('Veuillez sélectionner au moins un produit.') ;
  543. }
  544. },
  545. checkCreditLimit: function(order) {
  546. var total = this.priceTotal() ;
  547. if(order != null) {
  548. total = this.priceTotal() - order.amount_paid ;
  549. }
  550. return this.producer.credit_limit == null || (this.producer.credit_limit != null && (this.user.credit - total >= this.producer.credit_limit)) ;
  551. },
  552. isProductAvailable: function(product) {
  553. return product.productDistribution && product.productDistribution[0] && product.productDistribution[0].active == 1;
  554. },
  555. countProductsByCategory: function(category) {
  556. var count = 0 ;
  557. for(var i = 0 ; i < this.products.length ; i++) {
  558. if(this.products[i].id_product_category == category.id && this.isProductAvailable(this.products[i])) {
  559. count ++ ;
  560. }
  561. }
  562. return count ;
  563. },
  564. countSelectedProductsByCategory: function(category) {
  565. var count = 0 ;
  566. for(var key in this.products) {
  567. if(this.products[key].quantity_form > 0 && this.products[key].id_product_category == category.id) {
  568. count ++ ;
  569. }
  570. }
  571. return count ;
  572. },
  573. setCategoryCurrent: function(category, first) {
  574. if(this.categoryCurrent && this.categoryCurrent.id == category.id && !first) {
  575. this.categoryCurrent = null ;
  576. }
  577. else {
  578. this.categoryCurrent = category ;
  579. }
  580. setTimeout(function() {
  581. opendistrib_products();
  582. }, 500);
  583. }
  584. },
  585. computed : {
  586. orderedPointsSale: function() {
  587. var orderedPointsSaleArray = this.pointsSale.sort(function(a, b) {
  588. if(a.position > b.position) {
  589. return 1 ;
  590. }
  591. else {
  592. return -1 ;
  593. }
  594. }) ;
  595. return orderedPointsSaleArray ;
  596. }
  597. },
  598. updated: function () {
  599. var app = this;
  600. this.$nextTick(function () {
  601. if(app.step == 'payment' && !app.user && app.producer.option_allow_order_guest) {
  602. $("#signup-guest form").validate({
  603. rules: {
  604. 'SignupForm[email]': {
  605. 'email': true,
  606. 'required': true,
  607. 'minlength': 8,
  608. 'maxlength': 255
  609. },
  610. 'SignupForm[password]': {
  611. 'required': true,
  612. 'minlength': 8,
  613. "maxlength": 255
  614. },
  615. 'SignupForm[firstname]': {
  616. 'required': true,
  617. 'minlength': 2,
  618. "maxlength": 255
  619. },
  620. 'SignupForm[lastname]': {
  621. 'required': true,
  622. 'minlength': 2,
  623. "maxlength": 255
  624. },
  625. 'SignupForm[phone]': {
  626. 'required': true,
  627. 'minlength': 2,
  628. "maxlength": 255
  629. },
  630. },
  631. messages: {
  632. 'SignupForm[email]' : {
  633. 'required': 'Ce champs est requis.',
  634. 'email' : 'Email invalide.'
  635. },
  636. 'SignupForm[password]' : {
  637. 'required': 'Ce champs est requis.',
  638. },
  639. 'SignupForm[firstname]' : {
  640. 'required': 'Ce champs est requis.',
  641. },
  642. 'SignupForm[lastname]' : {
  643. 'required': 'Ce champs est requis.',
  644. },
  645. 'SignupForm[phone]' : {
  646. 'required': 'Ce champs est requis.',
  647. },
  648. }
  649. }) ;
  650. }
  651. });
  652. }
  653. });
  654. Vue.component('step-date',{
  655. props: [
  656. 'step',
  657. 'pointSaleActive',
  658. 'dateFormat',
  659. 'changeStep',
  660. 'producer',
  661. 'first',
  662. ],
  663. data: function() {
  664. return {
  665. } ;
  666. },
  667. template: '#template-step-date',
  668. methods: {
  669. }
  670. }) ;
  671. Vue.component('step-point-sale',{
  672. props: [
  673. 'step',
  674. 'pointSaleActive',
  675. 'changeStep',
  676. 'producer',
  677. 'first',
  678. ],
  679. data: function() {
  680. return {
  681. } ;
  682. },
  683. template: '#template-step-point-sale',
  684. methods: {
  685. }
  686. }) ;