From 3dc686840c181514be62ecdfbb4c18a132db9bec Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 27 Apr 2021 17:18:20 +0200 Subject: [PATCH] front adaptation to cartItems fix payzen customer cart creation TODO: refactor the payOnSite modals --- app/controllers/api/payzen_controller.rb | 12 +++++-- .../src/javascript/controllers/events.js.erb | 9 ++--- .../src/javascript/directives/cart.js | 36 ++++++++++--------- app/models/cart_item/payment_schedule.rb | 2 +- lib/pay_zen/helper.rb | 14 ++++---- 5 files changed, 44 insertions(+), 29 deletions(-) diff --git a/app/controllers/api/payzen_controller.rb b/app/controllers/api/payzen_controller.rb index 89396afc1..555a3693f 100644 --- a/app/controllers/api/payzen_controller.rb +++ b/app/controllers/api/payzen_controller.rb @@ -24,14 +24,16 @@ class API::PayzenController < API::PaymentsController client = PayZen::Charge.new @result = client.create_payment(amount: amount[:amount], order_id: @id, - customer: PayZen::Helper.generate_customer(params[:customer_id], params[:cart_items])) + customer: PayZen::Helper.generate_customer(params[:customer_id], current_user.id, params[:cart_items])) + error_handling end def create_token @id = PayZen::Helper.generate_ref(cart_items_params, params[:customer_id]) client = PayZen::Charge.new @result = client.create_token(order_id: @id, - customer: PayZen::Helper.generate_customer(params[:customer_id], params[:cart_items])) + customer: PayZen::Helper.generate_customer(params[:customer_id], current_user.id, params[:cart_items])) + error_handling end def check_hash @@ -68,4 +70,10 @@ class API::PayzenController < API::PaymentsController def on_subscription_success(order_id, details) super(order_id, 'PayZen::Order', details) end + + def error_handling + return unless @result['status'] == 'ERROR' + + render json: { error: @result['answer']['detailedErrorMessage'] || @result['answer']['errorMessage'] }, status: :unprocessable_entity + end end diff --git a/app/frontend/src/javascript/controllers/events.js.erb b/app/frontend/src/javascript/controllers/events.js.erb index b573b09c0..f83f13d86 100644 --- a/app/frontend/src/javascript/controllers/events.js.erb +++ b/app/frontend/src/javascript/controllers/events.js.erb @@ -195,7 +195,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' }); // once the dialog was closed, do things depending on the result modalInstance.result.then(function (res) { - if (res.status == 'success') { + if (res.status === 'success') { $state.go('app.public.events_list'); } }); @@ -636,7 +636,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' */ const mkCartItems = function (reservation, coupon, paymentMethod = '') { return { - customer_id: reservation.user_id, + customer_id: $scope.ctrl.member.id, reservation, coupon_code: ((coupon ? coupon.code : undefined)), payment_method: paymentMethod, @@ -684,7 +684,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' return Price.compute(mkCartItems(reservation, $scope.coupon.applied, 'card')).$promise; }, wallet () { - return Wallet.getWalletByUser({ user_id: reservation.user_id }).$promise; + return Wallet.getWalletByUser({ user_id: $scope.ctrl.member.id }).$promise; }, cgv () { return CustomAsset.get({ name: 'cgv-file' }).$promise; @@ -744,6 +744,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' * @param reservation {Object} to book */ const payOnSite = function (reservation) { + // FIXME, this may be broken, see cart.js#payOnSite $uibModal.open({ templateUrl: '/shared/valid_reservation_modal.html', size: 'sm', @@ -755,7 +756,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' return Price.compute(mkCartItems(reservation, $scope.coupon.applied)).$promise; }, wallet () { - return Wallet.getWalletByUser({ user_id: reservation.user_id }).$promise; + return Wallet.getWalletByUser({ user_id: $scope.ctrl.member.id }).$promise; }, coupon () { return $scope.coupon.applied; diff --git a/app/frontend/src/javascript/directives/cart.js b/app/frontend/src/javascript/directives/cart.js index 021f4e270..13b691d3c 100644 --- a/app/frontend/src/javascript/directives/cart.js +++ b/app/frontend/src/javascript/directives/cart.js @@ -695,35 +695,34 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', /** * Open a modal window that allows the user to process a credit card payment for his current shopping cart. */ - const payOnline = function (reservation) { + const payOnline = function (items) { // check that the online payment is enabled if ($scope.settings.online_payment_module !== 'true') { growl.error(_t('app.shared.cart.online_payment_disabled')); } else { $scope.toggleOnlinePaymentModal(() => { - $scope.onlinePayment.cartItems = mkCartItems([reservation], 'card'); + $scope.onlinePayment.cartItems = mkCartItems(items, 'card'); }); } }; /** * Open a modal window that allows the user to process a local payment for his current shopping cart (admin only). */ - const payOnSite = function (reservation) { + const payOnSite = function (items) { + // TODO, refactor to use cartItems: we had to remove the reservation object. $uibModal.open({ templateUrl: '/shared/valid_reservation_modal.html', size: $scope.schedule.payment_schedule ? 'lg' : 'sm', resolve: { - reservation () { - return reservation; - }, price () { - return Price.compute(mkCartItems([reservation], '')).$promise; + return Price.compute(mkCartItems(items, '')).$promise; }, cartItems () { - return mkCartItems([reservation], $scope.method.payment_method); + // these items are used in case of payment schedule. By default, the schedule is meant to be paid by card + return mkCartItems(items, 'card'); }, wallet () { - return Wallet.getWalletByUser({ user_id: reservation.user_id }).$promise; + return Wallet.getWalletByUser({ user_id: $scope.user.id }).$promise; }, coupon () { return $scope.coupon.applied; @@ -741,8 +740,8 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', return $scope.settings; } }, - controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', 'Subscription', 'wallet', 'helpers', '$filter', 'coupon', 'selectedPlan', 'schedule', 'cartItems', 'user', 'settings', - function ($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation, Subscription, wallet, helpers, $filter, coupon, selectedPlan, schedule, cartItems, user, settings) { + controller: ['$scope', '$uibModalInstance', '$state', 'price', 'Auth', 'Reservation', 'Subscription', 'wallet', 'helpers', '$filter', 'coupon', 'selectedPlan', 'schedule', 'cartItems', 'user', 'settings', + function ($scope, $uibModalInstance, $state, price, Auth, Reservation, Subscription, wallet, helpers, $filter, coupon, selectedPlan, schedule, cartItems, user, settings) { // user wallet amount $scope.wallet = wallet; @@ -752,8 +751,7 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', // Price to pay (wallet deducted) $scope.amount = helpers.getAmountToPay(price.price, wallet.amount); - // Reservation (simple & cartItems format) - $scope.reservation = reservation; + // Reservation &| subscription $scope.cartItems = cartItems; // Subscription @@ -914,18 +912,24 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', * Actions to pay slots (or subscription) */ const paySlots = function () { - const reservation = mkReservation($scope.events.reserved); + const items = []; + if ($scope.selectedPlan) { + items.push(mkSubscription($scope.selectedPlan.id)); + } + if ($scope.reservation.slots_attributes.length > 0) { + items.push(mkReservation($scope.events.reserved)); + } return Wallet.getWalletByUser({ user_id: $scope.user.id }, function (wallet) { const amountToPay = helpers.getAmountToPay($scope.amountTotal, wallet.amount); if ((AuthService.isAuthorized(['member']) && (amountToPay > 0 || (amountToPay === 0 && hasOtherDeadlines()))) || (AuthService.isAuthorized('manager') && $scope.user.id === $rootScope.currentUser.id && amountToPay > 0)) { - return payOnline(reservation); + return payOnline(items); } else { if (AuthService.isAuthorized(['admin']) || (AuthService.isAuthorized('manager') && $scope.user.id !== $rootScope.currentUser.id) || (amountToPay === 0 && !hasOtherDeadlines())) { - return payOnSite(reservation); + return payOnSite(items); } } }); diff --git a/app/models/cart_item/payment_schedule.rb b/app/models/cart_item/payment_schedule.rb index 18e096104..3740da460 100644 --- a/app/models/cart_item/payment_schedule.rb +++ b/app/models/cart_item/payment_schedule.rb @@ -11,7 +11,7 @@ class CartItem::PaymentSchedule end def schedule(total, total_without_coupon) - schedule = if @requested && @plan.monthly_payment + schedule = if @requested && @plan&.monthly_payment PaymentScheduleService.new.compute(@plan, total_without_coupon, coupon: @coupon.coupon) else nil diff --git a/lib/pay_zen/helper.rb b/lib/pay_zen/helper.rb index e31bcc15b..f783b6167 100644 --- a/lib/pay_zen/helper.rb +++ b/lib/pay_zen/helper.rb @@ -28,8 +28,10 @@ class PayZen::Helper end ## Generate a hash map compatible with PayZen 'V4/Customer/Customer' - def generate_customer(customer_id, cart_items) + def generate_customer(customer_id, operator_id, cart_items) customer = User.find(customer_id) + operator = User.find(operator_id) + address = if customer.organization? customer.invoicing_profile.organization.address&.address else @@ -49,20 +51,20 @@ class PayZen::Helper category: customer.organization? ? 'COMPANY' : 'PRIVATE', shippingMethod: 'ETICKET' }, - shoppingCart: generate_shopping_cart(cart_items, customer) + shoppingCart: generate_shopping_cart(cart_items, customer, operator) } end ## Generate a hash map compatible with PayZen 'V4/Customer/ShoppingCart' - def generate_shopping_cart(cart_items, customer) - cs = CartService.new(current_user) + def generate_shopping_cart(cart_items, customer, operator) + cs = CartService.new(operator) cart = cs.from_hash(cart_items) { cartItemInfo: cart.items.map do |item| { - productAmount: item.price, + productAmount: item.price[:amount].to_i.to_s, productLabel: item.name, - productQty: 1, + productQty: 1.to_s, productType: customer.organization? ? 'SERVICE_FOR_BUSINESS' : 'SERVICE_FOR_INDIVIDUAL' } end