de tintalimon: pague lo que pueda

This commit is contained in:
f 2021-10-27 16:12:18 -03:00
parent a1fd00908b
commit bba8bfa9aa
3 changed files with 344 additions and 0 deletions

125
_includes/donacion.html Normal file
View file

@ -0,0 +1,125 @@
{% comment %}
Traer la donación pasada como parámetro o la que se haya establecido por
defecto para el layout correspondiente.
product = producto
page = post que incluye esta donación
icon = ícono del botón
class = clases extra para el botón
boton = texto opcional para el botón
{% endcomment %}
{%- assign product = include.product | default: include.page -%}
{%- assign donacion = include.page.donacion | default: product.donacion -%}
<input data-controller="open" data-action="donacion" type="checkbox" id="donacion" class="d_toggler sr-only">
<label class="btn-block" for="donacion">
<span class="btn {{ include.class }} btn-block">
{{ include.boton | default: donacion.boton }}
{% if include.icon %}
<i class="{{ include.icon }}"></i>
{% endif %}
</span>
<div class="telon d_share-box"></div>
</label>
<form
data-pay-what-you-can-target="form"
{% include_cached pay_what_you_can_controller.html product=product url=include.page.pdf.path %}
style="z-index: 1011"
class="d_share-box pointer-event-none d_toggled d-flex align-items-center justify-content-center"
itemscope
itemtype="https://schema.org/Offer">
<meta itemprop="sku" content="{{ product.sku }}" />
<meta itemprop="availableDeliveryMethod" content="http://purl.org/goodrelations/v1#DirectDownload" />
<meta itemprop="acceptedPaymentMethod" content="http://purl.org/goodrelations/v1#PayPal" />
<div class="box inside background-white pointer-event-auto row no-gutters align-items-center justify-content-center p-5">
<div class="row">
<div class="col-md-9 black font-weight-light lead text-md-justify hyphens-md e-content">
{{ donacion.content | markdownify }}
</div>
<div class="col-md-3 d-flex justify-content-center">
{% if include.page.image.path %}
<picture>
<source srcset="{{ include.page.image.path | thumbnail: nil, 370 }}" media="(max-width: 767px)" />
<img class="cover shadow w-200px" src="{{ include.page.image.path | thumbnail: nil, 300 }}" loading="lazy" />
</picture>
{% else %}
{% include_cached logo_horizontal.svg %}
{% endif %}
</div>
<div class="col-md-3 mb-3 mb-md-0">
<h2>{{ site.i18n.donacion.monto }}</h2>
<label class="sr-only" for="price">{{ site.i18n.donacion.monto }}</label>
<input id="price" name="price" type="number" class="form-control" min="1" value="1" data-name="price" data-action="pay-what-you-can#store" required/>
</div>
<div class="col-md-3 mb-3 mb-md-0">
<div class="row">
<div class="col-6">
<input id="currency-ars" type="radio" class="sr-only" name="currency" value="ARS" data-name="currency" data-action="pay-what-you-can#store" required/>
<label for="currency-ars" itemprop="priceCurrency" class="d-flex flex-column justify-content-center">
<span class="btn border mb-3">ARS</span>
{% include mp-logo.svg %}
</label>
</div>
<div class="col-6">
<input id="currency-usd" type="radio" class="sr-only" name="currency" value="USD" data-name="currency" data-action="pay-what-you-can#store" required/>
<label for="currency-usd" itemprop="priceCurrency" class="d-flex flex-column justify-content-center">
<span class="btn border mb-3">USD</span>
{% include pp-logo.svg %}
</label>
</div>
<div class="col-12 text-center">
{% comment %}
Este input invisible es para que Bootstrap pueda mostrar el
error si querés mandar el formulario sin elegir una moneda.
{% endcomment %}
<input type="radio" class="d-none" name="currency" value="" />
<div class="invalid-feedback">
{{ site.i18n.donacion.currency }}
</div>
<p data-controller="cart-paypal-confirmation"></p>
</div>
</div>
</div>
<div class="col-md-3">
<button class="btn btn-primary btn-block mb-2" data-action="pay-what-you-can#pay">
<span class="hide-when-disabled">{{ donacion.boton }}</span>
<span class="show-when-disabled">
<span class="sr-only">{{ site.i18n.donacion.espera }}</span>
<i class="fa fa-fw fa-spinner fa-spin"></i>
</span>
</button>
{% if include.page.pdf.path %}
<div class="d-flex align-items-center justify-content-between">
<a
download
href="{{ include.page.pdf.path | uri_escape }}"
class="btn btn-transparent border black btn-block">
{{ site.i18n.libro.download }}
</a>
</div>
{% endif %}
</div>
<div class="col-md-3"></div>
<div class="col-12">
{{ site.i18n.donacion.medios | markdownify | replace: '<p>', '<p class="mb-0 mt-3"><small>' | replace: '</p>', '</small></p>' }}
</div>
</div>
</div>
</form>

View file

@ -0,0 +1,13 @@
data-controller="pay-what-you-can"
data-pay-what-you-can-download-value="{{ include.product.url | present }}"
data-pay-what-you-can-url-value="{{ include.url | default: include.product.url }}"
data-pay-what-you-can-variant-id-value="{{ include.product.variant_id }}"
data-pay-what-you-can-firstname-value="{{ include.product.title }}"
data-pay-what-you-can-currency-value="ARS"
data-pay-what-you-can-price-value="1"
data-image="{{ include.product.image.path | thumbnail: 300 }}"
data-title="{{ include.product.title }}"
data-price="{{ include.product.price }}"
data-in-stock="{{ include.product.in_stock }}"
data-stock="{{ include.product.stock }}"
data-extra="{{ include.extra | join: '|' }}"

View file

@ -0,0 +1,206 @@
import { CartBaseController } from './cart_base_controller'
/*
* Al pagar lo que podamos, primero hay que crear una orden y luego
* contactarse con la APIv2 para generar la variante con el precio que
* queramos agregar. Agregamos la variante al carrito y lanzamos el
* proceso de pago.
*/
export default class extends CartBaseController {
static targets = [ 'form' ]
static values = {
variantId: Number,
currency: String,
price: Number,
firstname: String
}
connect () {
this.paymentMethodByCurrency = {
ARS: 'Spree::PaymentMethod::MercadoPago',
USD: 'Spree::PaymentMethod::Paypal'
}
}
store (event) {
const target = event.currentTarget || event.target
this[`${target.dataset.name}Value`] = target.value
}
set formDisable (disable) {
this.formTarget.elements.forEach(x => x.disabled = disable)
}
/*
* Realiza todos los pasos:
*
* * Crear pedido
* * Crear variante con el monto y moneda
* * Agregar al pedido
* * Agregar dirección al pedido
* * Obtener métodos de envío
* * Obtener métodos de pago
* * Pagar
* * Reenviar a confirmación
* * Ejecutar el pago (si aplica)
*/
async pay (event = undefined) {
if (event) {
event.preventDefault()
event.stopPropagation()
}
if (!this.formTarget.checkValidity()) {
this.formTarget.classList.add('was-validated')
return
}
this.formDisable = true
// Crear pedido. Todos los pedidos van a ser hechos desde
// Argentina, no hay forma de cambiar esto.
const orderToken = await this.tempCartCreate()
const quantity = 1
const include = 'line_items'
const currency = this.currencyValue
const price = this.priceValue
const email = 'noreply@sutty.nl'
const firstname = this.firstnameValue
const lastname = '-'
const address1 = '-'
const country_id = 250 // XXX: Internet
const city = '-'
const phone = '11111111'
const zipcode = '1111'
const ship_address_attributes = { firstname, lastname, address1, city, country_id, zipcode, phone }
const bill_address_attributes = ship_address_attributes
const confirmation_delivered = true
const custom_return_url = this.customReturnUrl()
let variant_id = this.variantIdValue
// Crear la variante
const payWhatYouCanResponse = await this.spree.sutty.payWhatYouCan({ orderToken }, { variant_id, price, currency, quantity })
variant_id = payWhatYouCanResponse.data.id
if (!variant_id) {
this.formDisable = false
console.error('No se pudo generar la variante', { variant_id, price, currency, quantity })
return
}
// Configurar la moneda del pedido
let response = await this.spree.sutty.updateOrder({ orderToken }, { currency, confirmation_delivered, custom_return_url })
if (response.status > 299) {
console.error(response)
this.formDisable = false
return
}
// Agregar al carrito
response = await this.spree.cart.addItem({ orderToken }, { variant_id, quantity, include })
if (response.isFail()) {
this.handleFailure(response)
this.formDisable = false
return
}
// Actualizar la dirección
response = await this.spree.checkout.orderUpdate({ orderToken }, { order: { email, ship_address_attributes, bill_address_attributes }})
if (response.isFail()) {
this.handleFailure(response)
this.formDisable = false
return
}
// Obtener los medios de envío
response = await this.spree.checkout.shippingMethods({ orderToken }, { include: 'shipping_rates' })
if (response.isFail()) {
this.handleFailure(response)
this.formDisable = false
return
}
// Elegir medio de envío
response = await this.spree.checkout.orderUpdate({ orderToken }, {
order: {
shipments_attributes: [{
id: response.success().data[0].id,
selected_shipping_rate_id: response.success().included.filter(x => x.type == 'shipping_rate')[0].id
}]
}
})
// Elegir medio de pago
response = await this.spree.checkout.paymentMethods({ orderToken })
if (response.isFail()) {
this.handleFailure(response)
this.formDisable = false
return
}
const payment_method_id = response.success().data.find(x => this.paymentMethodByCurrency[this.currencyValue] == x.attributes.type).id
response = await this.spree.checkout.orderUpdate({ orderToken },
{
order: { payments_attributes: [{ payment_method_id }] },
payment_source: {
[payment_method_id]: {
name: 'Pepitx',
month: 12,
year: 2021
}
}
})
if (response.isFail()) {
this.handleFailure(response)
this.formDisable = false
return
}
response = await this.spree.checkout.complete({ orderToken })
if (response.isFail()) {
this.handleFailure(response)
this.formDisable = false
return
}
// Reenviar al medio de pago
const checkoutUrls = await this.spree.sutty.getCheckoutURL({ orderToken })
const redirectUrl = checkoutUrls.data[0]
Turbolinks.visit(redirectUrl)
// Volver
}
async tempCartCreate () {
const response = await this.spree.cart.create()
// If we fail here it's probably a server error, so we inform the
// user.
if (response.isFail()) {
this.handleFailure(response)
return
}
return response.success().data.attributes.token
}
// @return [String]
customReturnUrl () {
const url = new URL(window.location.href)
url.searchParams.set('open', '')
return url.toString()
}
}