Программно изменять пользовательские панели оформления заказа в зависимости от количества в корзине
В процессе оформления заказа мне нужно собрать дополнительные данные в зависимости от количества в корзине.
О чем это?
- Клиенты бронируют поездки
- Для аргументации предположим, что 2 пары влюбленных бронируют неделю в Венеции: они добавят 4 "поездки в Венецию" в корзину
- Во время оформления заказа я собираю обычные данные клиента, а также дополнительную информацию (имя, паспорт, день рождения...) для каждого другого участника в динамическая настраиваемая панель.
Моя текущая работа:
- Настройте пользовательскую панель с Панелями коммерческих групп полей , отключенными по умолчанию
- Добавьте правило с Дополнительными правилами торговли , которое включает панель, если кол-во > 1 для определенного типа продукта
- Затем с помощью
MYMODULE_form_FORM_ID_alter
я попробовал 2 разных способа добавления соответствующих полей:
Первый: дублируйте всю пользовательскую панель на странице оформления заказа :
function vts_commerce_form_commerce_checkout_form_checkout_alter(&$form, &$form_state, $form_id) {
$order = $form_state['build_info']['args'][0];
//load line item
$line_item = commerce_line_item_load($order->commerce_line_items['und'][0]['line_item_id']);
//get quantity
$qty = round($line_item->quantity);
//duplicate the pane for each participant (minus the customer user)
for($n=1; $n<$qty; $n++) {
$form['commerce_fieldgroup_pane__group_pax_sup_'.$n] = array_merge(array(), $form['commerce_fieldgroup_pane__group_pax_sup']);
}
}
В панель дублируется нормально, но поля дублированных панелей не сохраняются и не отображаются на следующем шаге. Может быть, потому, что я должен сообщить системе, что эти ЯВЛЯЮТСЯ областями проверки, +последующие обратные вызовы (как в модуле checkout_pane_example) ?
Если это так, я не нахожу , как объявить добавленные панели контрольными внутри этого цикла.
Второе: дублируйте каждое поле пользовательской панели внутри самой панели оформления заказа :
function vts_commerce_form_commerce_checkout_form_checkout_alter(&$form, &$form_state, $form_id) {
$order = $form_state['build_info']['args'][0];
//load line item
$line_item = commerce_line_item_load($order->commerce_line_items['und'][0]['line_item_id']);
//get quantity
$qty = round($line_item->quantity);
//duplicate the pane for each participant (minus the customer user)
for($n = 1; $n<$qty; $n++) {
foreach ($form['commerce_fieldgroup_pane__group_pax_sup'] as $key => $value) {
//searching fields into the fieldgroup array
if(substr($key, 0, 5) == 'field') {
//we duplicate the field
$form['commerce_fieldgroup_pane__group_pax_sup'][$key.'_'.$n] = array_merge(array(), $form['commerce_fieldgroup_pane__group_pax_sup'][$key]);
//rename field to have it unique
$form['commerce_fieldgroup_pane__group_pax_sup'][$key.'_'.$n]['und'][0]['#field_name'] = $form['commerce_fieldgroup_pane__group_pax_sup'][$key.'_'.$n]['und'][0]['#field_name'].'_'.$n;
//add it to the fieldgroup : NOT SURE WHICH IS THE RIGHT ONE OR IF I MUST LEAVE ALL
$group_pax_sup = $form['commerce_fieldgroup_pane__group_pax_sup']['#groups']['group_pax_sup'];
$group_pax_sup->children[] = $key.'_'.$n;
$form['commerce_fieldgroup_pane__group_pax_sup']['#group_children'][$key.'_'.$n] = 'group_pax_sup' ;
}
}
}
Это правильное добавление полей, но опять же ничего не сохраняется и не отображается на следующих шагах. Здесь кажется, что мне не удается правильно добавить поля в группу полей?
Как я мог этого добиться? Большое вам спасибо!
2 answers
Мне пришло в голову, что может быть хороший способ сделать это с помощью contrib, поэтому я опущу его, но для этого требуется, чтобы разные части хорошо сочетались, что не всегда происходит (:
Я вижу два три чистых подхода.
Использование API поля и contrib
Если вы хотите использовать API полей для создания/обновления/удаления полей, то я все еще думаю, что вам следует использовать пользовательские продукты линейки. Я немного удивлен, что у него нет возможности отображение встроенной формы при оформлении заказа. Возможно, для добавления этого будет создан модуль, он должен быть относительно простым. Но в то же время это может помочь вам с существующим контентом:
- Установка редактируемые поля и Панель представлений коммерции.
- Создайте настраиваемый тип позиции для настраиваемого продукта. Добавьте необходимые поля, но не настраивайте их так, чтобы они отображались в форме добавления в корзину. Также убедитесь, что позиции не могут быть объединены.
- Создать представление позиции, которое принимает идентификатор заказа в качестве аргумента, и добавляет поля, которые вы хотите отредактировать (и предоставляет им редактируемый формат). Добавьте фильтр, чтобы убедиться, что он отображает только позиции правильного пакета. Вы можете протестировать представление в режиме предварительного просмотра, создав новый заказ с несколькими настраиваемыми продуктами, найти идентификатор заказа (например, на странице оформления заказа) и передать этот идентификатор заказа в предварительный просмотр представлений. Он должен показать вам строку для каждой настраиваемой строки. Я бы не стал пытаться заставить панель представлений работать пока он не заработает в режиме предварительного просмотра.
- Добавьте это представление в качестве области оформления заказа.
- Сделайте круг из соли вокруг сервера и прошепчите молитву.
Использование API полей и комбинированных позиций (включает код)
Если вы хотите, чтобы у одной строки было несколько настроек, вам нужно настроить поля, чтобы разрешить это.
- Создайте коллекцию полей с нужными вам полями.
- Добавьте коллекцию многозначных полей этого введите соответствующий тип позиции (убедитесь, что он не будет отображаться в форме добавления в корзину).
- Создайте собственную панель оформления заказа, в которой отображается форма редактирования поля. Вы бы прочитали количество из позиции и отобразили только это количество полей (поскольку это поле с несколькими значениями, оно сохранится нормально, сколько бы их ни было).
Создание пользовательской панели и хранение данных, упорядоченных по порядку (включает код)
У этого есть недостатки, которые вы не можете использовать API полей для настраивайте, изменяйте или считывайте поля (так что никаких представлений). checkout_pane_example.модуль показывает, как это сделать, добавив псевдоним и второе поле электронной почты и сохранив данные вместе с заказом.
Уродливый метод
Я думаю, что вы, вероятно, могли бы сделать это с помощью панелей Commerce Fieldgroup, если создадите коллекцию полей с нужными вам полями, а затем добавите ее в качестве многозначного поля в объект заказа. Вам понадобится некоторый код, чтобы гарантировать, что только правильное количество коллекций полей показано (чтобы соответствовать количеству позиций, которые необходимо настроить). Этот метод кажется грязным и имеет два конкретных недостатка, о которых я могу подумать:
- По мере добавления новых настраиваемых продуктов объект заказа будет получать все больше и больше полей.
- Вы не можете связать настройки с определенной позицией (что делать, если я хочу, чтобы на моем красном свитере было одно сообщение, а на синем свитере - другое - какое сообщение идет с какой позицией?).
Я закончил использовать 2-е решение Энди, используя API полей и комбинированные позиции.
Создайте коллекцию полей с нужными вам полями. Добавьте коллекцию полей с несколькими значениями этого типа в соответствующую строку введите (убедитесь, что он не будет отображаться в форме добавления в корзину). Создайте свою собственную панель оформления заказа, в которой отображается форма редактирования поля.
Поскольку я некоторое время боролся с некоторыми аспектами API, особенно с коллекцией полей , вот мой полный панель оформления заказа .module
, может быть, это кому-нибудь поможет.
/**
* Implements hook_commerce_checkout_pane_info().
*/
function vts_commerce_checkout_pane_info() {
$panes['paxsup_pane'] = array(
'title' => t('Other Participants'),
'base' => 'vts_pane',
'name' => t('Other Participants'),
'page' => 'checkout',
'weight' => -5,
);
return $panes;
}
/**
* Implements hook_pane_checkout_form().
*/
function vts_pane_checkout_form($form, &$form_state, $checkout_pane, $order) {
//load the current line item.
$line_item = commerce_line_item_load($order->commerce_line_items['und'][0]['line_item_id']);
$pane_form = array();
if ($checkout_pane['pane_id'] == 'paxsup_pane') {
field_attach_form('commerce_line_item', $line_item, $pane_form, $form_state, NULL, array('field_name' => 'field_paxsup'));
}
return $pane_form;
}
/*
* Change general GUI edit field cardinality range from 1->1 to 1->20
*/
function vts_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
// Increase the max cardinality to 20
$range = drupal_map_assoc(range(1, 20));
$new_options = array(FIELD_CARDINALITY_UNLIMITED => t('Unlimited')) + $range;
// Change the options
$form['field']['cardinality']['#options'] = $new_options;
}
/*
* Implements hook_form_FORM_ID_alter().
*/
function vts_form_commerce_checkout_form_checkout_alter(&$form, &$form_state, $form_id) {
//Load line item to get pax number
$line_item = commerce_line_item_load($form_state['build_info']['args'][0]->commerce_line_items['und'][0]['line_item_id']);
$paxsup_nb = $line_item->quantity -1;
if($paxsup_nb > 0){
//Unset unnecessary items of paxsup field
for($n=19; $n > $paxsup_nb-1; $n--){
unset($form['paxsup_pane']['field_paxsup']['und'][$n]);
}
//Fill in paxsup with session values
for($n=0; $n<$paxsup_nb; $n++){
$form['paxsup_pane']['field_paxsup']['und'][$n]['field_paxsup_foo']['und']['#default_value'][0] = isset($_SESSION['paxsup_foo_'.$n])? $_SESSION['paxsup_foo_'.$n]:'';
$form['paxsup_pane']['field_paxsup']['und'][$n]['field_paxsup_bar']['und'][0]['value']['#default_value'] = isset($_SESSION['paxsup_bar_'.$n])? $_SESSION['paxsup_bar_'.$n]:'';
$form['paxsup_pane']['field_paxsup']['und'][$n]['field_paxsup_date_of_birth']['und'][0]['#default_value']['value'] = isset($_SESSION['paxsup_date_of_birth_'.$n])? $_SESSION['paxsup_date_of_birth_'.$n]:'';
}
}
else {
unset($form['paxsup_pane']);
}
}
/**
* Implements hook_pane_checkout_form_validate().
*/
function vts_pane_checkout_form_validate($form, &$form_state, $checkout_pane, $order) {
$line_item = commerce_line_item_load($order->commerce_line_items['und'][0]['line_item_id']);
$paxsup_nb = $line_item->quantity -1;
if($paxsup_nb > 0){
for($n=0; $n<$paxsup_nb;$n++) {
if(empty($form_state['values']['field_paxsup']['und'][$n]['field_paxsup_foo']['und'][0]['value'])
|| empty($form_state['values']['field_paxsup']['und'][$n]['field_paxsup_bar']['und'][0]['value'])
|| empty($form_state['values']['field_paxsup']['und'][$n]['field_paxsup_date_of_birth']['und'][0]['value']) ) {
return FALSE;
}
}
}
return TRUE;
}
/**
* Implements hook_pane_checkout_form_submit().
*/
function vts_pane_checkout_form_submit($form, &$form_state, $checkout_pane, $order) {
$line_item = commerce_line_item_load($order->commerce_line_items['und'][0]['line_item_id']);
$paxsup_nb = $line_item->quantity -1;
if($paxsup_nb > 0){
//Set paxsup SESSION values
for($n=0; $n<$paxsup_nb;$n++) { //
$_SESSION['paxsup_foo_'.$n] = $form_state['values']['field_paxsup']['und'][$n]['field_paxsup_foo']['und'][0]['value'];
$_SESSION['paxsup_bar_'.$n] = $form_state['values']['field_paxsup']['und'][$n]['field_paxsup_bar']['und'][0]['value'];
$_SESSION['paxsup_date_of_birth_'.$n] = $form_state['values']['field_paxsup']['und'][$n]['field_paxsup_date_of_birth']['und'][0]['value'];
}
// Add the paxsup values to the line_item fields
if (!empty($form_state['values']['field_paxsup'])) {
if(0 == count($line_item->field_paxsup)){
//CREATE A NEW PAXSUP SET
$entity = entity_load_single('commerce_line_item', $line_item->line_item_id);
$wrapper = entity_metadata_wrapper('commerce_line_item', $entity);
$collections = array();
for($n=0; $n<$paxsup_nb;$n++) { //
$fc = entity_create('field_collection_item', array('field_name' => 'field_paxsup'));
$fc->setHostEntity('commerce_line_item', $line_item, LANGUAGE_NONE, FALSE);
$fc->field_paxsup_foo['und'][0] = array('value'=> $form_state['values']['field_paxsup']['und'][$n]['field_paxsup_foo']['und'][0]['value']);
$fc->field_paxsup_bar['und'][0] = array('value'=> $form_state['values']['field_paxsup']['und'][$n]['field_paxsup_bar']['und'][0]['value']);
$fc->field_paxsup_date_of_birth['und'][0] = array('value'=> $form_state['values']['field_paxsup']['und'][$n]['field_paxsup_date_of_birth']['und'][0]['value']);
$fc->save(TRUE);
$collections[] = $fc;
}
//Set the field collection items via the wrapper.
$wrapper->field_paxsup->set($collections);
$wrapper->save();
}
else {
//UPDATE FIELD COLLECTION
for($n=0; $n<$paxsup_nb;$n++) { //
$fc = entity_load_single('field_collection_item', $line_item->field_paxsup['und'][$n]['value'] );
$fc->field_paxsup_foo['und'][0] = array('value'=> $form_state['values']['field_paxsup']['und'][$n]['field_paxsup_foo']['und'][0]['value']);
$fc->field_paxsup_bar['und'][0] = array('value'=> $form_state['values']['field_paxsup']['und'][$n]['field_paxsup_bar']['und'][0]['value']);
$fc->field_paxsup_date_of_birth['und'][0] = array('value'=> $form_state['values']['field_paxsup']['und'][$n]['field_paxsup_date_of_birth']['und'][0]['value']);
$fc->save(TRUE);
}
}
}
}
}
/**
* Implements hook_pane_review().
*
*/
function vts_pane_review($form, $form_state, $checkout_pane, $order) {
$line_item = commerce_line_item_load($order->commerce_line_items['und'][0]['line_item_id']);
$paxsup_nb = $line_item->quantity -1;
if (!empty($line_item->field_paxsup['und'][0])) {
$view = '';
for($n=0; $n<$paxsup_nb;$n++) {
$paxsup = entity_load_single('field_collection_item', $line_item->field_paxsup['und'][$n]['value'] );
$display = array('label' => 'hidden');
$foo = field_view_field('field_collection_item', $paxsup, 'field_paxsup_foo', $display);
$bar = field_view_field('field_collection_item', $paxsup, 'field_paxsup_bar', $display);
$date = field_view_field('field_collection_item', $paxsup, 'field_paxsup_date_of_birth', $display);
$view .= '<p>'.$foo[0]['#markup'] .' '. $bar[0]['#markup'] .' '. $prenom[0]['#markup'] .t(', né(e) le '). $date[0]['#markup'] .'</p>';
}
return $view;
}
}