Hi folks,
I need to have a user input field for a payment method, baisally a text input filed that's presented when the payment method is selected.
( ) paypal
() other 1
(x) my payment method
Please enter code [___________]
Any hints?
TIA!
you can over ride the protected function getPluginHtml () and provide a field but I assume there is a lot more to it than that.. what is the field supposed to do?
Hi GJC Web Design,
thank your for your reply.
This particular "payment method" just needs to pass a string with the customer's account number along with the order.
A shopper field would be fit the case better, as it would be stored into the customer's profile, but shopper fields are not be conditional for the specify payment method.
Cheers!
in that case u could use some JS to show/hide and enforce the shopper field if that radio is chosen
I never use Javascript for required functionality, as it is possibly disabled.
Cheers!
Quote from: vmfyelloq19 on August 14, 2019, 08:49:59 AM
I never use Javascript for required functionality, as it is possibly disabled.
As VirtueMart makes heavy use of JavaScript then AFAIK someone with js "disabled" would be unable to use the store, anyway.
Hi jenkinhill,
You are right, and I adjusted my opinion on requiring JS with VM.
I've added some custom user text fields, added some JS to hide them via CSS if the payment mezhod does not match.
But that's causing several issues:
- I cannot set the fields to required
- there is no way to add a custom validation
Any hints anyone?
TIA!
just do it with JS
example
if(jQuery('#companyreg_field').prop('checked')) {
jQuery('#first_name_field').removeClass('required');
jQuery('#first_name_field').removeAttr('required aria-required');
}else{
jQuery('#first_name_field').addClass('required')
jQuery('#first_name_field').attr('required', 'required');
jQuery('#first_name_field').attr('aria-required', 'true');
}
validation can be handled the same way with e.g.
jQuery('input#your_input ').bind("focusout keyup change", function() {
// do stuff
});
or on submit etc
Thank you GJC Web Design,
that helped a lot!
After some consideration I'm giving the paymnet plugin another go.
I managed to display the required user input fields using plgVmDisplayListFEPayment().
I can check user input just fine in plgVmOnSelectCheckPayment() by checking the values I get from vRequest::getString([...]).
Still I'm stuck with re-displaying user input in the layout called from plgVmDisplayListFEPayment().
It seems user input is empty here.
I also tried to settting a class variable ($this->myformdata) in plgVmOnSelectCheckPayment() but it this var is empty in plgVmDisplayListFEPayment(). Might be a method-call ordering thing.
So what's the proper way to fill in the former user input in the form fields?
<input type... value="<insert former user input here>" ... />
What I have so far in plugins/vmpayment/mypayment/mypayment.php is:
class plgVmpaymentMypayment extends vmPSPlugin {
[...]
public function plgVmDisplayListFEPayment(VirtueMartCart $cart, $selected=0, &$htmlIn) {
if ($this->getPluginMethods($cart->vendorId) === 0) {
if (empty($this->_name)) {
$app=JFactory::getApplication();
$app->enqueueMessage(vmText::_('COM_VIRTUEMART_CART_NO_' . strtoupper($this->_psType)));
return false;
} else {
return false;
}
}
$htmlarray=[];
foreach ($this->methods as $this->_currentMethod) {
if($this->checkConditions($cart, $this->_currentMethod, $cart->cartPrices)) {
$cartPrices=$cart->cartPrices;
$methodSalesPrice=$this->calculateSalesPrice($cart, $this->_currentMethod, $cartPrices);
$payment_cost='';
if ($methodSalesPrice) {
$payment_cost=$currency->priceDisplay($methodSalesPrice);
}
if ($selected == $this->_currentMethod->virtuemart_paymentmethod_id) {
$checked='checked="checked"';
} else {
$checked='';
}
/*
*
* Need to pass former user input into layout here
* If possible: also result of validation to highlight bad input fields
*
*/
$html=$this->renderByLayout('display_payment', [
'plugin' => $this->_currentMethod
,'checked' => $checked
,'payment_cost' => $payment_cost
]);
$htmlarray[]=$html;
if (!empty($htmlarray)) {
$htmlIn[]=$htmlarray;
}
}
}
return true;
} // plgVmDisplayListFEPayment()
[...]
public function plgVmOnSelectCheckPayment(VirtueMartCart $cart, &$msg) {
if(! $this->selectedThisByMethodId($cart->virtuemart_paymentmethod_id)) {
return NULL; // Another method was selected, do nothing
}
[...] // [my checks here]
if($errors) {
vmWarn($errormessage);
return false;
} else {
// Just return true?
return $this->OnSelectCheck($cart);
}
} // plgVmOnSelectCheckPayment()
I could not find a "proper" way to save/recall/pass user input to my form.
Please find what I managed so far after fidling around, trying to make sense of vm source etc.
I'm storing user input data in the user's session to be able to recall it later.
Here's the relevant plugin code, plus a stub to render the html form fields required.
User input get's saved to database automatically as announced in constructor.
Hope it helps someone looking for something similar.
[Update: fixed copy/paste error / missing methods]
* htdocs/plugins/vmpayment/mypayment.php:
<?php
defined ('_JEXEC') or die();
use Joomla\CMS\Factory;
if(! class_exists('vmPSPlugin')) require(VMPATH_PLUGINLIBS . DS . 'vmpsplugin.php');
class plgVmpaymentMypayment extends vmPSPlugin {
private $_formdata=[];
function __construct(& $subject, $config) {
parent::__construct($subject, $config);
$this->_loggable = true;
$this->tableFields = array_keys($this->getTableSQLFields());
$this->_tablepkey = 'id'; //virtuemart_directdebit_id';
$this->_tableId = 'id'; //'virtuemart_directdebit_id';
$varsToPush=[
'myvar1' => array('', 'char')
,'myvar2' => array('', 'char')
,'myvar3' => array('', 'char')
];
$this->addVarsToPushCore($varsToPush, 1);
$this->setConfigParameterable($this->_configTableFieldName, $varsToPush);
this->setConvertable(array('min_amount','max_amount','cost_per_transaction','cost_min_transaction'));
$this->setConvertDecimal(array('min_amount','max_amount','cost_per_transaction','cost_min_transaction','cost_percent_total'));
} // __construct();
function getTableSQLFields() {
return [
'id' => 'int(11) UNSIGNED NOT null AUTO_INCREMENT'
,'virtuemart_order_id' => 'int(1) UNSIGNED'
,'order_number' => 'char(64)'
,'virtuemart_paymentmethod_id' => 'mediumint(1) UNSIGNED'
,'payment_name' => 'varchar(5000)' // might include html
,'payment_order_total' => 'decimal(15,5) NOT null DEFAULT \'0.00000\''
,'payment_currency' => 'char(3) '
,'email_currency' => 'smallint(1)'
,'cost_per_transaction' => 'decimal(10,2)'
,'cost_percent_total' => 'decimal(10,2)'
,'tax_id' => 'smallint(1)'
,'myvar1' => 'varchar(255)'
,'myvar3' => 'varchar(255)'
,'myvar3' => 'varchar(255)'
];
} // getTableSQLFields()
public function plgVmDisplayListFEPayment(VirtueMartCart $cart, $selected = 0, &$htmlIn) {
if ($this->getPluginMethods($cart->vendorId) === 0) {
if (empty($this->_name)) {
$app = JFactory::getApplication();
$app->enqueueMessage(vmText::_('COM_VIRTUEMART_CART_NO_' . strtoupper($this->_psType)));
return false;
} else {
return false;
}
}
$method_name = $this->_psType . '_name';
$currentMethod_id_key = 'virtuemart_' . $this->_psType . 'method_id';
$session = JFactory::getSession();
// get/store user input in session as there seems to be "official" way to keep it
$session_node=$this->_type . '__' . $this->_name;
$session_data = $session->get($session_node);
foreach($this->methods as $this->_currentMethod) {
if($this->checkConditions($cart, $this->_currentMethod, $cart->cartPrices)) {
$html = '';
$cartPrices=$cart->cartPrices;
if (isset($this->_currentMethod->cost_method)) {
$cost_method=$this->_currentMethod->cost_method;
} else {
$cost_method=true;
}
$methodSalesPrice = $this->setCartPrices($cart, $cartPrices, $this->_currentMethod, $cost_method);
$payment_name_html = $this->renderPluginName($this->_currentMethod);
$key=$method_name . '_html';
$this->_currentMethod->$key=$payment_name_html;
$this->_currentMethod->payment_currency = $this->getPaymentCurrency($this->_currentMethod);
$pluginmethod_id = $this->_idName;
$checked=($selected == $this->_currentMethod->$pluginmethod_id);
$html=$this->renderByLayout('display_payment', [
// passed to template as $viewData[]:
'plugin' => $this->_currentMethod
,'checked' => $checked
,'payment_cost' => $methodSalesPrice
,'formdata' => $session_data
]);
$htmlIn[$this->_psType][$this->_currentMethod->$currentMethod_id_key] =$html;
} // if this->checkConditions
} // foreach($this->methods)
return true;
} // plgVmDisplayListFEPayment()
public function plgVmOnSelectCheckPayment(VirtueMartCart $cart, &$msg) {
if(! $this->selectedThisByMethodId($cart->virtuemart_paymentmethod_id)) {
return null; // Another method was selected, do nothing
}
if(! ($this->_currentMethod = $this->getVmPluginMethod($cart->virtuemart_paymentmethod_id))) {
return false;
}
if(! $this->selectedThisByMethodId($cart->virtuemart_paymentmethod_id)) {
return null; // Another method was selected, do nothing
}
$userinput_result=$this->_userinput_validate($cart); // result: true|array of string with errormessage. More data in $this->_formdata
// Fire a user warning:
if(is_array($userinput_result)) {
array_map('vmWarn', $userinput_result); // see helpers/vmecho.php for vmWarn(), vmInfo(), ...
return false;
}
return true;
} // plgVmOnSelectCheckPayment()
function plgVmConfirmedOrder($cart, $order) {
if(! ($this->_currentMethod = $this->getVmPluginMethod($order['details']['BT']->virtuemart_paymentmethod_id))) {
return null; // Another method was selected, do nothing
}
if(! $this->selectedThisElement($this->_currentMethod->payment_element)) {
return false;
}
$session = JFactory::getSession();
$session_node=$this->_type . '__' . $this->_name;
$session_data = $session->get($session_node);
$this->_currentMethod->payment_currency = $this->getPaymentCurrency($this->_currentMethod,$order['details']['BT']->payment_currency_id);
$payment_name = $this->renderPluginName($this->_currentMethod, $order);
$currency_code_3 = shopFunctions::getCurrencyByID($this->_currentMethod->payment_currency, 'currency_code_3');
$email_currency = $this->getEmailCurrency($this->_currentMethod);
$totalInPaymentCurrency = vmPSPlugin::getAmountInCurrency($order['details']['BT']->order_total,$this->_currentMethod->payment_currency);
// Prepare data that should be stored in the database
$dbValues['order_number'] = $order['details']['BT']->order_number;
$dbValues['virtuemart_paymentmethod_id'] = $cart->virtuemart_paymentmethod_id;
$dbValues['payment_name'] = $payment_name;
$dbValues['payment_order_total'] = $totalInPaymentCurrency['value']; // from standard plugin
$dbValues['payment_currency'] = $currency_code_3; // from standard plugin
$dbValues['email_currency'] = $email_currency;
$dbValues['cost_per_transaction'] = (float) @$this->_currentMethod->cost_per_transaction;
$dbValues['cost_min_transaction'] = (float) @$this->_currentMethod->cost_min_transaction; // from standard plugin
$dbValues['cost_percent_total'] = (float) @$this->_currentMethod->cost_percent_total; // from standard plugin
$dbValues['tax_id'] = $this->_currentMethod->tax_id;
$dbValues['myvar1'] = $session_data['myvar1']['value'];
$dbValues['myvar2'] = $session_data['myvar2']['value'];
$dbValues['myvar3'] = $session_data['myvar3']['value'];
$this->storePSPluginInternalData($dbValues); // returns full dataset array incl. new dbid
} // plgVmConfirmedOrder()
/**
* _userinput_validate()
* param $cart
* return true|array of strings with error messages.
* Additonal data in $this->_formdata[
* (string) value
* (string) inputkey
* (bool) valid
* (string) errormessage, if any
* ]
*/
private function _userinput_validate($cart) {
$session = JFactory::getSession();
$session_node=$this->_type . '__' . $this->_name;
$session_data = $session->get($session_node);
if(is_null($session_data)) $session_data = [];
$input = Factory::getApplication()->input;
$errors=[];
$inputkey='virtuemart_paymentmethod_' . $cart->virtuemart_paymentmethod_id . '_' . 'myvar1';
$value=trim($input->get($inputkey, null, 'string'));
if(null===$value) {
if(! empty($session_data[$key]['value'])) $value=$session_data[$key]['value'];
}
$formdata_dataset=[
'value'=>$value
,'inputkey'=>$inputkey
,'valid'=>true
,'errormessage'=>''
];
$langkey='MYPAYMENTPLUGIN_' . strtoupper($key);
// Just check if not empty
// Sample validation for empty value:
if(empty($value)) {
$formdata_dataset['valid']=false;
$formdata_dataset['errormessage']=vmText::sprintf('COM_VIRTUEMART_MISSING_VALUE_FOR_FIELD', JText::_($langkey));
}
if(! empty($formdata_dataset['errormessage'])) $errors[]=$formdata_dataset['errormessage'];
$this->_formdata[$key]=$formdata_dataset;
$session_data[$key]=$formdata_dataset; // store in session - have no other way to push data to layout?
// DO MORE VALIDATIONS HERE
$session->set($session_node, $session_data);
if(empty($errors)) {
return true;
} else {
return $errors;
}
} // _userinput_validate()
// [...]
} / class
* htdocs/plugins/vmpayment/myfancypayment/tmpl/display_payment.php:<?php
defined ('_JEXEC') or die();
// Render our fancy pamyner input fields here:
// Previous entered form data in $viewData['formdata'] etc.
// if($viewData ['checked'] ) ...
// echo '<label for=...
// echo '<input type=....
Hi folks,
anyone has a hint on how to get and show the plugin's data as stored during checkout?
For the order detail page I see my plugin's plgVmOnShowOrderFEPayment() get's fired, and I see I can set $payment_name.
a) What method does get called for the order email?
b) How would I retrieve the data? Do I need to do the DB selects for #__virtuemart_payment_plg_mypayment myself or is there a method for this?
TIA!