Ecco lo scoop: Ubercart non è in grado di gestire (con gli strumenti di amministrazione) questo che pensavo essere un requisito abbastanza standard, cioè la possibilità di rendere disponibili alcune tariffe di spedizione flatrate invece di altre in base al tipo di pagamento scelto (es. pago con carta di credito => pago meno di spedizione, pago in contrassegno => la spedizione costa di più).
Attenzione, nelle azioni condizionali per il flatrate è disponibile l'opzione di controllare il tipo di pagamento, ma non funziona, per il semplice motivo che al momento della visualizzazione del form di checkout l'oggetto $order non ha ancora al suo interno i dati di pagamento (spero che questa rivelazione faccia risparmiare a qualcun altro le ore che ho perso io - e il nervoso - nella ricerca del perché le CA non funzionassero). Per lo stesso motivo, non funzionerebbe neanche usare del codice PHP come condizione della CA.
Che fare quindi?
La mia soluzione è sicuramente piuttosto "hack", ma in attesa di avere più tempo per migliorarla, tutto sommato non è così sporca.
Il problema è che nel form di checkout le spese di spedizione sono calcolate al volo usando JS, quindi dobbiamo passare un po' di dati da PHP a JS (tra poco vedremo come).
L'obiettivo è fornire qualche parametro in più al callback che gestisce la richiesta dell'elenco di tipi di spedizione disponibili, ogni volta che si preme il pulsante per aggiornare il calcolo; inoltre, dobbiamo fare in modo che il calcolo e la visualizzazione delle opzioni disponibili si aggiorni automaticamente non solo quando si modifica l'indirizzo di spedizione, ma anche quando si cambia la scelta del tipo di pagamento.
Il callback di cui si diceva è uc_quote_request_quotes e viene chiamato da una voce di menu cart/checkout/shipping/quote
Questo menu item viene inserito tra i parametri disponibili alle chiamate JS della pagina, inserito in Drupal.settings, uno dei 2 principali "ponti" fra PHP e JS forniti da Drupal (l'altro è Drupal.behaviors). Per fare un override di quel callback dovremo chiamare la funzione con un altro menu item, che porterà con sé un parametro aggiuntivo: io l'ho chiamato cart/checkout/shipping/alterquote/%
Il parametro servirà a passare alla funzione il tipo di pagamento prescelto (supponiamo per esempio di avere "paypal" per la carta di credito e "cod" per il contrassegno).
La funzione chiamata dal menu item sarà uc_miomodulo_quote_request_quotes e sarà una copia precisa di uc_quote_request_quotes, con qualche aggiunta finale. Qui viene la parte più "sporca" della cosa: dato che non c'è modo di usare l'amministrazione per associare tipi di pagamento e tipi di spedizione, dovremo farlo a mano qui, usando un array, tipo:
$pm_m_ar = array(
'flatrate_1' => 'paypal',
'flatrate_2' => 'cod',
'flatrate_3' => 'paypal',
'flatrate_4' => 'cod',
'flatrate_5' => 'paypal',
'flatrate_6' => 'cod',
'flatrate_7' => 'paypal',
);
In cui "flatrate_n" sono gli ID delle tariffe flatrate di spedizione.
A questo punto posso modificare il pezzo finale della funzione, in cui viene generato l'elenco dei tipi di spedizione. Dove c'era
foreach ($quote_data as $method_id => $options) {
foreach ($options as $accsrl => $data) {
$return_quotes[$method_id .'---'. $accsrl] = $data;
}
}
inserisco
foreach ($quote_data as $method_id => $options) {
// filtro tipi di spedizione previsti in base a tipo pagamento
if ($pm_m_ar[$method_id] == $paymethod) {
foreach ($options as $accsrl => $data) {
$return_quotes[$method_id .'---'. $accsrl] = $data;
}
}
}
$paymethod è l'altra novità che introduciamo nella funzione: si tratta del parametro che passiamo attraverso la URL e che viene letto dalla funzione. Nella mia funzione si legge così
uc_miomodulo_quote_request_quotes($paymethod = 'paypal')
Il valore di default corrisponde al tipo di pagamento di default preimpostato.
Sul versante PHP il grosso del lavoro è fatto, adesso dobbiamo avvisare JS dei cambiamenti.
Dobbiamo:
- Cambiare il valore predefinito della URL in Drupal.settings
- Aggiungere qualcosa all'azione che viene eseguita quando si seleziona il tipo di pagamento
Il primo obiettivo, lo raggiungiamo con un hook_init che verrà richiamato (opportunamente filtrato in base al path) al caricamento della pagina:
function uc_miomodulo_init() {
// modifico l'URL predefinito per callback calcolo spese spedizione
// aggiunto parametro che serve a identificare tipo di pagamento
// viene utilizzato per filtrare quali spese di spediz. mostrare
if (arg(0) == 'cart' && arg(1) == 'checkout') {
drupal_add_js('Drupal.settings.ucURL.shippingQuotes = \'/cart/checkout/shipping/alterquote/paypal\'', 'inline');
}
}
Il secondo, con hook_form_alter, in cui modifico l'URL e aggiungo l'attivazione del "trigger" che provoca l'aggiornamento delle spese di spedizione dopo il clic sull'opzione.
function uc_miomodulo_form_alter(&$form, $form_state, $form_id) {
if ($form_id == 'uc_cart_checkout_form') {
$form['panes']['payment']['payment_method']['#attributes'] = array('onclick' => "get_payment_details(Drupal.settings.ucURL.checkoutPaymentDetails + this.value); Drupal.settings.ucURL.shippingQuotes = '/cart/checkout/shipping/alterquote/' + this.value; triggerQuoteCallback();");
}
}
Per finire, ecco il menu item:
// callback per calcolo spese di spedizione
$items['cart/checkout/shipping/alterquote/%'] = array(
'page callback' => 'uc_miomodulo_quote_request_quotes',
'page arguments' => array(4),
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
Ciao Pinolo,
ci ho sbattuto la testa oggi per la prima volta e anche io sono sorpreso.
Se ho capito bene tu non fai altro che modificare in automatico il metodo di spedizione una volta selezionata l'opzione di pagamento COD, giusto?
Credo che adesso si possa fare senza toccare il codice grazie ad un aggiornamento di Ubercart che permette di usare ajax per aggiornare i pannelli del checkout che vuoi tu definendo delle Rules & Actions..
Il problema è che io uso UPS con l'integrazione che mi fornisce le quotazioni in automatico, e dovrei quindi AGGIUNGERE a QUESTE un costo fisso. Altrimenti sarei costretto a farmi un doppio listone di tutti i costi di spedizione in base ai vari paesi ( x2 per farli con e senza COD).
Alla fine ho trovato questo: https://drupal.org/project/uc_pma
Per drupal 7 (che ho io) e' un dev portato dalla 6.. ma per adesso tutto bene, apparte un piccolo bug.
Semplicemente aggiunge una linea sotto il Subtotal con un altro aggiustamento di prezzo, con il nome del metodo di pagamento associato + "fee".
Si puo configurare nella pagina dei Payment methods, dove per ognuno si puo mettere un valore assoluto o percentuale, negativo o positivo.
Molto semplice e utile.
Il bug:
quando si seleziona il metodo di pagamento che prevede una fee, e nel carrello e' presente un item che non e' un vero prodotto (node), ma nel mio caso uno sconto, e lo si vuole far vedere come riga a se stante anche nel riepilogo finale, questo viene scambiato in posizione sopra al Subtotale. I conti alla fine tornano, ma invece di avere:
Subtotal: 100
Welcome Discount: -10
COD fee: +5
Order total: 95
Ho:
Welcome Discount: -10
Subtotal: 100
COD fee: +5
Order total: 95
Qualcuno ha esperienze in merito?
Qualcuno che sa come risolvere il piccolo bug?
Grazie
Lorenzo Giovenali
https://wear-freaky.com