1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-18 07:52:23 +01:00

verify each deadlines on payzen for payment schedules

This commit is contained in:
Sylvain 2021-06-03 12:22:37 +02:00
parent 4e109f7edb
commit dc0a75e52d
17 changed files with 105 additions and 44 deletions

View File

@ -1,5 +1,5 @@
import axios, { AxiosInstance } from 'axios'
// compile
const token: HTMLMetaElement = document.querySelector('[name="csrf-token"]');
const client: AxiosInstance = axios.create({
headers: {

View File

@ -137,7 +137,7 @@
<script type="text/ng-template" id="addOnlineInfo.html">
<table class="invoice-element-legend">
<tr><td><strong>X[{{ 'app.admin.invoices.text' | translate }}]</strong></td><td>{{ 'app.admin.invoices.add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned' | translate }} <mark translate>{{ 'app.admin.invoices.this_will_never_be_added_when_a_refund_notice_is_present' }}</mark> {{ 'app.admin.invoices.eg_XVL_will_add_VL_to_the_invoices_settled_with_stripe' | translate }}</td></tr>
<tr><td><strong>X[{{ 'app.admin.invoices.text' | translate }}]</strong></td><td>{{ 'app.admin.invoices.add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned' | translate }} <mark translate>{{ 'app.admin.invoices.this_will_never_be_added_when_a_refund_notice_is_present' }}</mark> {{ 'app.admin.invoices.eg_XVL_will_add_VL_to_the_invoices_settled_by_card' | translate }}</td></tr>
</table>
</script>

View File

@ -98,11 +98,11 @@ class Coupon < ApplicationRecord
private
def create_gateway_coupon
PaymentGatewayService.create_coupon(id)
PaymentGatewayService.new.create_coupon(id)
end
def delete_gateway_coupon
PaymentGatewayService.delete_coupon(id)
PaymentGatewayService.new.delete_coupon(id)
end
end

View File

@ -34,4 +34,20 @@ class PaymentGatewayService
def create_or_update_product(klass, id)
@gateway.create_or_update_product(klass, id)
end
def process_payment_schedule_item(payment_schedule_item)
service = case payment_schedule_item.payment_schedule.gateway_subscription.klass
when /^PayZen::/
require 'pay_zen/service'
PayZen::Service
when /^Stripe::/
require 'stripe/service'
Stripe::Service
else
require 'payment/service'
Payment::Service
end
gateway = service.new
gateway.process_payment_schedule_item(payment_schedule_item)
end
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
# create PaymentSchedules for various items
# perform various operations on PaymentSchedules
class PaymentScheduleService
##
# Compute a payment schedule for a new subscription to the provided plan
@ -184,7 +184,7 @@ class PaymentScheduleService
subscription = payment_schedule_item.payment_schedule.payment_schedule_objects.find(&:subscription).subscription
if payment_schedule_item.payment_schedule.main_object.object_type == Reservation.name
details[:reservation] = payment_schedule_item.details['other_items']
reservation = payment_schedule_item.payment_schedule.main_object
reservation = payment_schedule_item.payment_schedule.main_object.reservation
end
# the wallet transaction

View File

@ -17,35 +17,10 @@ class PaymentScheduleItemWorker
end
def check_item(psi)
# the following depends on the payment method (stripe/check)
# FIXME
# the following depends on the payment method (card/check)
if psi.payment_schedule.payment_method == 'card'
### Stripe
stripe_key = Setting.get('stripe_secret_key')
stp_subscription = psi.payment_schedule.gateway_subscription.retrieve
stp_invoice = Stripe::Invoice.retrieve(stp_subscription.latest_invoice, api_key: stripe_key)
if stp_invoice.status == 'paid'
##### Stripe / Successfully paid
PaymentScheduleService.new.generate_invoice(psi, payment_method: 'card', payment_id: stp_invoice.payment_intent, payment_type: 'Stripe::PaymentIntent') # FIXME
psi.update_attributes(state: 'paid', payment_method: 'card', stp_invoice_id: stp_invoice.id)
elsif stp_subscription.status == 'past_due' || stp_invoice.status == 'open'
##### Stripe / Payment error
if psi.state == 'new'
# notify only for new deadlines, to prevent spamming
NotificationCenter.call type: 'notify_admin_payment_schedule_failed',
receiver: User.admins_and_managers,
attached_object: psi
NotificationCenter.call type: 'notify_member_payment_schedule_failed',
receiver: psi.payment_schedule.user,
attached_object: psi
end
stp_payment_intent = Stripe::PaymentIntent.retrieve(stp_invoice.payment_intent, api_key: stripe_key)
psi.update_attributes(state: stp_payment_intent.status,
stp_invoice_id: stp_invoice.id,
client_secret: stp_payment_intent.client_secret)
else
psi.update_attributes(state: 'error')
end
### Cards
PaymentGatewayService.new.process_payment_schedule_item(psi)
elsif psi.state == 'new'
### Check (only new deadlines, to prevent spamming)
NotificationCenter.call type: 'notify_admin_payment_schedule_check_deadline',

View File

@ -472,7 +472,7 @@ de:
n_digits_annual_amount_of_orders: "(n) Ziffern, jährliche Anzahl von Bestellungen (z.B. yyyyy => 00012 : 12. Bestellung des Jahres"
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Fügen Sie nur dann eine Mitteilung zu den Online-Verkäufen hinzu, wenn die Rechnung betroffen ist."
this_will_never_be_added_when_a_refund_notice_is_present: "Dies wird nie hinzugefügt, wenn eine Rückerstattung vorhanden ist."
eg_XVL_will_add_VL_to_the_invoices_settled_with_stripe: '(z.B. fügt W[/VL] jenen Rechnungen "/VL" hinzu, die mit Stripe bezahlt werden)'
eg_XVL_will_add_VL_to_the_invoices_settled_by_card: '(z.B. fügt W[/VL] jenen Rechnungen "/VL" hinzu, die mit karte bezahlt werden)'
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Fügen Sie nur dann eine Mitteilung zu Erstattungen hinzu, wenn die Rechnung betroffen ist."
this_will_never_be_added_when_an_online_sales_notice_is_present: "Dies wird nie hinzugefügt, wenn eine Online-Verkaufsmitteilung vorhanden ist."
eg_RA_will_add_A_to_the_refund_invoices: '(z.B. fügt R[/A] den Rückerstattungsrechnungen "/A" hinzu)'

View File

@ -472,7 +472,7 @@ en:
n_digits_annual_amount_of_orders: "(n) digits, annual count of orders (ex. yyyyyy => 000008 : 8th order of this year)"
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Add a notice regarding the online sales, only if the invoice is concerned."
this_will_never_be_added_when_a_refund_notice_is_present: "This will never be added when a refund notice is present."
eg_XVL_will_add_VL_to_the_invoices_settled_with_stripe: '(eg. X[/VL] will add "/VL" to the invoices settled with stripe)'
eg_XVL_will_add_VL_to_the_invoices_settled_by_card: '(eg. X[/VL] will add "/VL" to the invoices settled by online card)'
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Add a notice regarding refunds, only if the invoice is concerned."
this_will_never_be_added_when_an_online_sales_notice_is_present: "This will never be added when an online sales notice is present."
eg_RA_will_add_A_to_the_refund_invoices: '(eg. R[/A] will add "/A" to the refund invoices)'

View File

@ -472,7 +472,7 @@ es:
n_digits_annual_amount_of_orders: "(n) dígitos, recuento anual de órdenes (ej: aaaaa => 000008: octava orden de este año)"
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Añadir un aviso con respecto a las ventas en línea, sólo si la factura es de interés."
this_will_never_be_added_when_a_refund_notice_is_present: "Esto nunca se agregará cuando se presente un aviso de reembolso."
eg_XVL_will_add_VL_to_the_invoices_settled_with_stripe: '(por ejemplo, X [/ VL] agregará "/ VL" a las facturas liquidadas con la raya)'
eg_XVL_will_add_VL_to_the_invoices_settled_by_card: '(por ejemplo, X [/ VL] agregará "/ VL" a las facturas liquidadas con tarjeta de crédito)'
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Añada un aviso con respecto a los reembolsos, sólo si la factura es de interés."
this_will_never_be_added_when_an_online_sales_notice_is_present: "Esto nunca se agregará cuando un aviso de venta en línea está presente."
eg_RA_will_add_A_to_the_refund_invoices: '(ed. R[/A] añadirá "/A" a las facturas de reembolso)'

View File

@ -472,7 +472,7 @@ fr:
n_digits_annual_amount_of_orders: "Nombre de commandes dans l'année, sur (n) chiffres (ex. yyyyyy => 000008 : 8ème commande cette année)"
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Ajoute une information relative à la vente en ligne, uniquement si cela concerne la facture."
this_will_never_be_added_when_a_refund_notice_is_present: "Ceci ne sera jamais cumulé avec une information de remboursement."
eg_XVL_will_add_VL_to_the_invoices_settled_with_stripe: '(ex. X[/VL] ajoutera "/VL" aux factures réglées avec stripe)'
eg_XVL_will_add_VL_to_the_invoices_settled_by_card: '(ex. X[/VL] ajoutera "/VL" aux factures réglées en ligne par carte bancaire)'
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Ajoute une information relative aux remboursements, uniquement si cela concerne la facture."
this_will_never_be_added_when_an_online_sales_notice_is_present: "Ceci ne sera jamais cumulé avec une information de vente en ligne."
eg_RA_will_add_A_to_the_refund_invoices: '(ex. R[/A] ajoutera "/A" aux factures de remboursement)'

View File

@ -472,7 +472,7 @@ pt:
n_digits_annual_amount_of_orders: "(n) dígitos, contagem anual de pedidos (ex. aaaaaa => 000008: oitava ordem deste ano)"
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Adicionar um aviso sobre as vendas on-line, somente se a fatura estiver envolvida."
this_will_never_be_added_when_a_refund_notice_is_present: "Isso nunca será adicionado quando uma notificação de reembolso estiver presente."
eg_XVL_will_add_VL_to_the_invoices_settled_with_stripe: '(ex. X[/VL] irá adicionar "/VL" às faturas liquidadas com lista)'
eg_XVL_will_add_VL_to_the_invoices_settled_by_card: '(ex. X[/VL] irá adicionar "/VL" às faturas liquidadas com cartão de crédito)'
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Adicionar um aviso sobre reembolsos, apenas se a fatura estiver envolvida."
this_will_never_be_added_when_an_online_sales_notice_is_present: "Isto nunca será adicionado quando uma notificação de vendas online estiver presente."
eg_RA_will_add_A_to_the_refund_invoices: '(ed. R[/A] irá adicionar "/A" nas faturas reembolsadas)'

View File

@ -472,7 +472,7 @@ zu:
n_digits_annual_amount_of_orders: "crwdns7437:0crwdne7437:0"
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "crwdns7439:0crwdne7439:0"
this_will_never_be_added_when_a_refund_notice_is_present: "crwdns7441:0crwdne7441:0"
eg_XVL_will_add_VL_to_the_invoices_settled_with_stripe: 'crwdns7443:0[/VL]crwdne7443:0'
eg_XVL_will_add_VL_to_the_invoices_settled_by_card: 'crwdns7443:0[/VL]crwdne7443:0'
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "crwdns7445:0crwdne7445:0"
this_will_never_be_added_when_an_online_sales_notice_is_present: "crwdns7447:0crwdne7447:0"
eg_RA_will_add_A_to_the_refund_invoices: 'crwdns21064:0[/A]crwdne21064:0'

View File

@ -446,7 +446,7 @@ en:
do_you_really_want_to_cancel_this_reservation_html: "<p>Do you really want to cancel this reservation?</p><p>Warning: if this reservation was made free of charge, as part of a subscription, the credits used will not be re-credited.</p>"
reservation_was_cancelled_successfully: "Reservation was cancelled successfully."
cancellation_failed: "Cancellation failed."
confirm_payment_of_html: "{METHOD, select, stripe{Pay by card} other{Pay on site}}: {AMOUNT}"
confirm_payment_of_html: "{METHOD, select, card{Pay by card} other{Pay on site}}: {AMOUNT}"
a_problem_occurred_during_the_payment_process_please_try_again_later: "A problem occurred during the payment process. Please try again later."
none: "None"
online_payment_disabled: "Online payment is not available. Please contact the FabLab's reception directly."
@ -497,7 +497,7 @@ en:
state_paid: "Paid"
state_error: "Error"
state_canceled: "Canceled"
method_stripe: "by card"
method_card: "by card"
method_check: "by check"
confirm_payment: "Confirm payment"
solve: "Solve"

View File

@ -446,7 +446,7 @@ fr:
do_you_really_want_to_cancel_this_reservation_html: "<p>Êtes-vous sur de vouloir annuler cette réservation ?</p><p>Attention : si cette réservation a été effectuée gratuitement, dans le cadre d'un abonnement, les crédits utilisés ne seront pas re-crédités.</p>"
reservation_was_cancelled_successfully: "La réservation a bien été annulée."
cancellation_failed: "L'annulation a échouée."
confirm_payment_of_html: "{METHOD, select, stripe{Payer par carte} other{Paiement sur place}} : {AMOUNT}"
confirm_payment_of_html: "{METHOD, select, card{Payer par carte} other{Paiement sur place}} : {AMOUNT}"
a_problem_occurred_during_the_payment_process_please_try_again_later: "Il y a eu un problème lors de la procédure de paiement. Veuillez réessayer plus tard."
none: "Aucune"
online_payment_disabled: "Le paiement par carte bancaire n'est pas disponible. Merci de contacter directement l'accueil du FabLab."
@ -497,7 +497,7 @@ fr:
state_paid: "Payée"
state_error: "Erreur"
state_canceled: "Annulée"
method_stripe: "par carte"
method_card: "par carte"
method_check: "par chèque"
confirm_payment: "Confirmer l'encaissement"
solve: "Résoudre"

View File

@ -3,6 +3,7 @@
require 'payment/service'
require 'pay_zen/charge'
require 'pay_zen/order'
require 'pay_zen/item'
# PayZen payement gateway
module PayZen; end
@ -47,6 +48,37 @@ class PayZen::Service < Payment::Service
pgo_sub.save!
end
def process_payment_schedule_item(payment_schedule_item)
pz_order = payment_schedule_item.payment_schedule.payment_gateway_objects.find { |pgo| pgo.gateway_object_type == 'PayZen::Order' }.gateway_object.retrieve
transaction = pz_order['answer']['transactions'].last
if transaction['status'] == 'PAID'
PaymentScheduleService.new.generate_invoice(payment_schedule_item,
payment_method: 'card',
payment_id: transaction['uuid'],
payment_type: 'PayZen::Transaction')
payment_schedule_item.update_attributes(state: 'paid', payment_method: 'card')
pgo = PaymentGatewayObject.find_or_initialize_by(item: payment_schedule_item)
pgo.gateway_object = PayZen::Item.new('PayZen::Transaction', transaction['uuid'])
pgo.save!
elsif transaction['status'] == 'RUNNING'
if payment_schedule_item.state == 'new'
# notify only for new deadlines, to prevent spamming
NotificationCenter.call type: 'notify_admin_payment_schedule_failed',
receiver: User.admins_and_managers,
attached_object: payment_schedule_item
NotificationCenter.call type: 'notify_member_payment_schedule_failed',
receiver: payment_schedule_item.payment_schedule.user,
attached_object: payment_schedule_item
end
payment_schedule_item.update_attributes(state: transaction['detailedStatus'])
pgo = PaymentGatewayObject.find_or_initialize_by(item: payment_schedule_item)
pgo.gateway_object = PayZen::Item.new('PayZen::Transaction', transaction['uuid'])
pgo.save!
else
payment_schedule_item.update_attributes(state: 'error')
end
end
private
def rrule(payment_schedule)

View File

@ -13,4 +13,6 @@ class Payment::Service
def delete_coupon(_coupon_id); end
def create_or_update_product(_klass, _id); end
def process_payment_schedule_item(_payment_schedule_item); end
end

View File

@ -84,6 +84,42 @@ class Stripe::Service < Payment::Service
amount
end
def process_payment_schedule_item(payment_schedule_item)
stripe_key = Setting.get('stripe_secret_key')
stp_subscription = payment_schedule_item.payment_schedule.gateway_subscription.retrieve
stp_invoice = Stripe::Invoice.retrieve(stp_subscription.latest_invoice, api_key: stripe_key)
if stp_invoice.status == 'paid'
##### Successfully paid
PaymentScheduleService.new.generate_invoice(payment_schedule_item,
payment_method: 'card',
payment_id: stp_invoice.payment_intent,
payment_type: 'Stripe::PaymentIntent')
payment_schedule_item.update_attributes(state: 'paid', payment_method: 'card')
pgo = PaymentGatewayObject.find_or_initialize_by(item: payment_schedule_item)
pgo.gateway_object = stp_invoice
pgo.save!
elsif stp_subscription.status == 'past_due' || stp_invoice.status == 'open'
##### Payment error
if payment_schedule_item.state == 'new'
# notify only for new deadlines, to prevent spamming
NotificationCenter.call type: 'notify_admin_payment_schedule_failed',
receiver: User.admins_and_managers,
attached_object: payment_schedule_item
NotificationCenter.call type: 'notify_member_payment_schedule_failed',
receiver: payment_schedule_item.payment_schedule.user,
attached_object: payment_schedule_item
end
stp_payment_intent = Stripe::PaymentIntent.retrieve(stp_invoice.payment_intent, api_key: stripe_key)
payment_schedule_item.update_attributes(state: stp_payment_intent.status,
client_secret: stp_payment_intent.client_secret)
pgo = PaymentGatewayObject.find_or_initialize_by(item: payment_schedule_item)
pgo.gateway_object = stp_invoice
pgo.save!
else
payment_schedule_item.update_attributes(state: 'error')
end
end
private
def subscription_invoice_items(payment_schedule, subscription, first_item, reservable_stp_id)