uc_attribute.admin.inc 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370
  1. <?php
  2. /**
  3. * @file
  4. * Attribute administration menu items.
  5. */
  6. /**
  7. * Displays a paged list and overview of existing product attributes.
  8. */
  9. function uc_attribute_admin() {
  10. $header = array(
  11. array('data' => t('Name'), 'field' => 'a.name', 'sort' => 'asc'),
  12. array('data' => t('Label'), 'field' => 'a.label'),
  13. t('Required'),
  14. array('data' => t('List position'), 'field' => 'a.ordering'),
  15. t('Number of options'),
  16. t('Display type'),
  17. array('data' => t('Operations'), 'colspan' => 3),
  18. );
  19. $display_types = _uc_attribute_display_types();
  20. $query = db_select('uc_attributes', 'a')->extend('PagerDefault')->extend('TableSort')
  21. ->fields('a', array('aid', 'name', 'label', 'required', 'ordering', 'display'))
  22. ->orderByHeader($header)
  23. ->limit(30);
  24. $rows = array();
  25. $result = $query->execute();
  26. foreach ($result as $attr) {
  27. $attr->options = db_query('SELECT COUNT(*) FROM {uc_attribute_options} WHERE aid = :aid', array(':aid' => $attr->aid))->fetchField();
  28. if (empty($attr->label)) {
  29. $attr->label = $attr->name;
  30. }
  31. $rows[] = array(
  32. check_plain($attr->name),
  33. check_plain($attr->label),
  34. $attr->required == 1 ? t('Yes') : t('No'),
  35. $attr->ordering,
  36. $attr->options,
  37. $display_types[$attr->display],
  38. l(t('edit'), 'admin/store/products/attributes/' . $attr->aid . '/edit'),
  39. l(t('options'), 'admin/store/products/attributes/' . $attr->aid . '/options'),
  40. l(t('delete'), 'admin/store/products/attributes/' . $attr->aid . '/delete'),
  41. );
  42. }
  43. $build['attributes'] = array(
  44. '#theme' => 'table',
  45. '#header' => $header,
  46. '#rows' => $rows,
  47. '#empty' => t('No product attributes have been added yet.'),
  48. );
  49. $build['pager'] = array(
  50. '#theme' => 'pager',
  51. );
  52. return $build;
  53. }
  54. /**
  55. * Form builder for product attributes.
  56. *
  57. * @see uc_attribute_form_submit()
  58. * @ingroup forms
  59. */
  60. function uc_attribute_form($form, &$form_state, $attribute = NULL) {
  61. // If an attribute specified, add its ID as a hidden value.
  62. if (!empty($attribute)) {
  63. $form['aid'] = array('#type' => 'value', '#value' => $attribute->aid);
  64. drupal_set_title(t('Edit attribute: %name', array('%name' => $attribute->name)), PASS_THROUGH);
  65. }
  66. if (isset($attribute->name)) {
  67. if (empty($attribute->label)) {
  68. $attribute->label = $attribute->name;
  69. }
  70. $name = $attribute->name;
  71. $label = $attribute->label;
  72. }
  73. else {
  74. $name = $label = '';
  75. }
  76. $form['name'] = array(
  77. '#type' => 'textfield',
  78. '#title' => t('Name'),
  79. '#description' => t('The name of the attribute used in administrative forms'),
  80. '#default_value' => $name,
  81. '#required' => TRUE,
  82. );
  83. $form['label'] = array(
  84. '#type' => 'textfield',
  85. '#title' => t('Label'),
  86. '#description' => t("Enter a label that customers will see instead of the attribute name. Use &lt;none&gt; if you don't want a title to appear at all."),
  87. '#default_value' => $label,
  88. );
  89. $form['description'] = array(
  90. '#type' => 'textfield',
  91. '#title' => t('Help text'),
  92. '#description' => t('<b>Optional.</b> Enter the help text that will display beneath the attribute on product add to cart forms.'),
  93. '#default_value' => isset($attribute->description) ? $attribute->description : '',
  94. '#maxlength' => 255,
  95. );
  96. $form['required'] = array(
  97. '#type' => 'checkbox',
  98. '#title' => t('Make this attribute required, forcing the customer to choose an option.'),
  99. '#description' => t('Selecting this for an attribute will disregard any default option you specify.<br />May be overridden at the product level.'),
  100. '#default_value' => isset($attribute->required) ? $attribute->required : 0,
  101. );
  102. $form['display'] = array(
  103. '#type' => 'select',
  104. '#title' => t('Display type'),
  105. '#description' => t('This specifies how the options for this attribute will be presented.<br />May be overridden at the product level.'),
  106. '#options' => _uc_attribute_display_types(),
  107. '#default_value' => isset($attribute->display) ? $attribute->display : 1,
  108. );
  109. $form['ordering'] = array(
  110. '#type' => 'weight',
  111. '#delta' => 25,
  112. '#title' => t('List position'),
  113. '#description' => t('Multiple attributes on an add to cart form are sorted by this value and then by their name.<br />May be overridden at the product level.'),
  114. '#default_value' => isset($attribute->ordering) ? $attribute->ordering : 0,
  115. );
  116. $form['actions'] = array('#type' => 'actions');
  117. $form['actions']['submit'] = array(
  118. '#type' => 'submit',
  119. '#value' => t('Submit'),
  120. '#suffix' => l(t('Cancel'), 'admin/store/products/attributes'),
  121. );
  122. return $form;
  123. }
  124. /**
  125. * Form submission handler for uc_attribute_form().
  126. *
  127. * @see uc_attribute_form()
  128. */
  129. function uc_attribute_form_submit($form, &$form_state) {
  130. if (!empty($form_state['values']['aid'])) {
  131. drupal_write_record('uc_attributes', $form_state['values'], 'aid');
  132. $form_state['redirect'] = 'admin/store/products/attributes';
  133. }
  134. else {
  135. drupal_write_record('uc_attributes', $form_state['values']);
  136. $form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options';
  137. }
  138. }
  139. /**
  140. * Confirms the deletion of the given attribute.
  141. *
  142. * @see uc_attribute_delete_confirm_submit()
  143. */
  144. function uc_attribute_delete_confirm($form, &$form_state, $attribute) {
  145. // If we got a bunk attribute, kick out an error message.
  146. if (empty($attribute)) {
  147. drupal_set_message(t('There is no attribute with that ID.'), 'error');
  148. drupal_goto('admin/store/products/attributes');
  149. }
  150. $form['aid'] = array('#type' => 'value', '#value' => $attribute->aid);
  151. $count = db_query("SELECT COUNT(*) FROM {uc_product_attributes} WHERE aid = :aid", array(':aid' => $attribute->aid))->fetchField();
  152. $output = confirm_form($form, t('Are you sure you want to delete the attribute %name?', array('%name' => $attribute->name)),
  153. 'admin/store/products/attributes', format_plural($count, 'There is 1 product with this attribute.', 'There are @count products with this attribute.'),
  154. t('Delete'), t('Cancel'));
  155. return $output;
  156. }
  157. /**
  158. * Form submission handler for uc_attribute_delete_confirm().
  159. *
  160. * @see uc_attribute_delete_confirm()
  161. */
  162. function uc_attribute_delete_confirm_submit($form, &$form_state) {
  163. if ($form_state['values']['confirm']) {
  164. $attribute = uc_attribute_load($form_state['values']['aid']);
  165. $options = array_keys($attribute->options);
  166. if ($options) {
  167. db_delete('uc_class_attribute_options')
  168. ->condition('oid', $options, 'IN')
  169. ->execute();
  170. db_delete('uc_product_options')
  171. ->condition('oid', $options, 'IN')
  172. ->execute();
  173. }
  174. if ($nodes = db_query("SELECT nid FROM {uc_product_attributes} WHERE aid = :aid", array(':aid' => $attribute->aid))->fetchCol()) {
  175. db_delete('uc_product_adjustments')
  176. ->condition('nid', $nodes, 'IN')
  177. ->execute();
  178. }
  179. db_delete('uc_class_attributes')
  180. ->condition('aid', $form_state['values']['aid'])
  181. ->execute();
  182. db_delete('uc_product_attributes')
  183. ->condition('aid', $form_state['values']['aid'])
  184. ->execute();
  185. db_delete('uc_attribute_options')
  186. ->condition('aid', $form_state['values']['aid'])
  187. ->execute();
  188. db_delete('uc_attributes')
  189. ->condition('aid', $form_state['values']['aid'])
  190. ->execute();
  191. drupal_set_message(t('Product attribute deleted.'));
  192. $form_state['redirect'] = 'admin/store/products/attributes';
  193. }
  194. }
  195. /**
  196. * Displays options and the modifications to products they represent.
  197. *
  198. * @see uc_attribute_options_form_validate()
  199. * @see uc_attribute_options_form_submit()
  200. * @ingroup forms
  201. */
  202. function uc_attribute_options_form($form, &$form_state, $attribute) {
  203. // Set an appropriate title.
  204. drupal_set_title(t('Options for %name', array('%name' => $attribute->name)), PASS_THROUGH);
  205. // Store the attribute ID in the form array.
  206. $form['aid'] = array(
  207. '#type' => 'value',
  208. '#value' => $attribute->aid,
  209. );
  210. $form['options'] = array();
  211. // Loop through all the options on an attribute.
  212. foreach ($attribute->options as $key => $data) {
  213. $form['options'][$key] = array(
  214. 'name' => array(
  215. '#markup' => check_plain($data->name),
  216. ),
  217. 'cost' => array(
  218. '#theme' => 'uc_price',
  219. '#price' => $data->cost,
  220. ),
  221. 'price' => array(
  222. '#theme' => 'uc_price',
  223. '#price' => $data->price,
  224. ),
  225. 'weight' => array(
  226. '#markup' => (string)$data->weight,
  227. ),
  228. 'ordering' => array(
  229. '#type' => 'weight',
  230. '#delta' => 50,
  231. '#default_value' => $data->ordering,
  232. '#attributes' => array('class' => array('uc-attribute-option-table-ordering')),
  233. ),
  234. 'edit' => array('#markup' => l(t('edit'), 'admin/store/products/attributes/' . $attribute->aid . '/options/' . $key . '/edit')),
  235. 'delete' => array('#markup' => l(t('delete'), 'admin/store/products/attributes/' . $attribute->aid . '/options/' . $key . '/delete')),
  236. );
  237. }
  238. if (count($form['options'])) {
  239. $form['options']['#tree'] = TRUE;
  240. $form['actions'] = array('#type' => 'actions');
  241. $form['actions']['submit'] = array(
  242. '#type' => 'submit',
  243. '#value' => t('Save changes'),
  244. '#weight' => 10,
  245. );
  246. }
  247. return $form;
  248. }
  249. /**
  250. * Form submission handler for uc_attribute_options_form().
  251. *
  252. * @see uc_attribute_options_form()
  253. * @see uc_object_options_form_submit()
  254. */
  255. function uc_attribute_options_form_submit($form, &$form_state) {
  256. foreach ($form_state['values']['options'] as $oid => $option) {
  257. db_update('uc_attribute_options')
  258. ->fields(array(
  259. 'ordering' => $option['ordering'],
  260. ))
  261. ->condition('oid', $oid)
  262. ->execute();
  263. }
  264. drupal_set_message(t('The changes have been saved.'));
  265. }
  266. /**
  267. * Formats an attribute and its options.
  268. *
  269. * @param $variables
  270. * An associative array containing:
  271. * - form: A render element representing the form.
  272. *
  273. * @ingroup themeable
  274. */
  275. function theme_uc_attribute_options_form($variables) {
  276. $form = $variables['form'];
  277. $header = array(t('Name'), t('Default cost'), t('Default price'), t('Default weight'), array('data' => t('List position'), 'sort' => 'asc'), array('data' => t('Operations'), 'colspan' => 2));
  278. $rows = array();
  279. foreach (element_children($form['options']) as $oid) {
  280. $rows[] = array(
  281. 'data' => array(
  282. drupal_render($form['options'][$oid]['name']),
  283. drupal_render($form['options'][$oid]['cost']),
  284. drupal_render($form['options'][$oid]['price']),
  285. drupal_render($form['options'][$oid]['weight']),
  286. drupal_render($form['options'][$oid]['ordering']),
  287. drupal_render($form['options'][$oid]['edit']),
  288. drupal_render($form['options'][$oid]['delete']),
  289. ),
  290. 'class' => array('draggable'),
  291. );
  292. }
  293. drupal_add_tabledrag('uc-attribute-option-table', 'order', 'sibling', 'uc-attribute-option-table-ordering');
  294. $output = theme('table', array(
  295. 'header' => $header,
  296. 'rows' => $rows,
  297. 'attributes' => array('id' => 'uc-attribute-option-table'),
  298. 'empty' => t('No options for this attribute have been added yet.'),
  299. ));
  300. $output .= drupal_render_children($form);
  301. return $output;
  302. }
  303. /**
  304. * Form builder for attribute options.
  305. *
  306. * @see uc_attribute_option_form_validate()
  307. * @see uc_attribute_option_form_submit()
  308. * @ingroup forms
  309. */
  310. function uc_attribute_option_form($form, &$form_state, $attribute, $option = NULL) {
  311. // If we got a bunk attribute, kick out an error message.
  312. if (empty($attribute)) {
  313. drupal_set_message(t('There is no attribute with that ID.'), 'error');
  314. drupal_goto('admin/store/products/attributes');
  315. }
  316. $aid = $attribute->aid;
  317. $form['aid'] = array('#type' => 'hidden', '#value' => $aid);
  318. if (!empty($option)) {
  319. $form['oid'] = array('#type' => 'hidden', '#value' => $option->oid);
  320. drupal_set_title(t('Edit option: %name', array('%name' => $option->name)), PASS_THROUGH);
  321. }
  322. else {
  323. $option = new stdClass();
  324. $option->name = '';
  325. $option->ordering = 0;
  326. $option->cost = 0;
  327. $option->price = 0;
  328. $option->weight = 0;
  329. drupal_set_title(t('Options for %name', array('%name' => $attribute->name)), PASS_THROUGH);
  330. }
  331. $form['name'] = array(
  332. '#type' => 'textfield',
  333. '#title' => t('Name'),
  334. '#description' => t('This name will appear to customers on product add to cart forms.'),
  335. '#default_value' => $option->name,
  336. '#required' => TRUE,
  337. '#weight' => 0,
  338. );
  339. $form['ordering'] = array(
  340. '#type' => 'weight',
  341. '#delta' => 50,
  342. '#title' => t('List position'),
  343. '#description' => t('Options will be listed sorted by this value and then by their name.<br />May be overridden at the product level.'),
  344. '#default_value' => $option->ordering,
  345. '#weight' => 4,
  346. );
  347. $form['adjustments'] = array(
  348. '#type' => 'fieldset',
  349. '#title' => t('Default adjustments'),
  350. '#description' => t('Enter a positive or negative value for each adjustment applied when this option is selected.<br />Any of these may be overriden at the product level.'),
  351. '#collapsible' => FALSE,
  352. '#weight' => 8,
  353. );
  354. $form['adjustments']['cost'] = array(
  355. '#type' => 'uc_price',
  356. '#title' => t('Cost'),
  357. '#default_value' => $option->cost,
  358. '#weight' => 1,
  359. '#allow_negative' => TRUE,
  360. );
  361. $form['adjustments']['price'] = array(
  362. '#type' => 'uc_price',
  363. '#title' => t('Price'),
  364. '#default_value' => $option->price,
  365. '#weight' => 2,
  366. '#allow_negative' => TRUE,
  367. );
  368. $form['adjustments']['weight'] = array(
  369. '#type' => 'textfield',
  370. '#title' => t('Weight'),
  371. '#default_value' => $option->weight,
  372. '#weight' => 3,
  373. );
  374. $form['actions'] = array('#type' => 'actions');
  375. $form['actions']['submit'] = array(
  376. '#type' => 'submit',
  377. '#value' => t('Submit'),
  378. '#suffix' => l(t('Cancel'), 'admin/store/products/attributes/' . $aid . '/options'),
  379. '#weight' => 10,
  380. );
  381. return $form;
  382. }
  383. /**
  384. * Validates number formats.
  385. *
  386. * @see uc_attribute_option_form()
  387. * @see uc_attribute_option_form_submit()
  388. */
  389. function uc_attribute_option_form_validate($form, &$form_state) {
  390. $pattern = '/^-?\d*(\.\d*)?$/';
  391. $price_error = t('This must be in a valid number format. No commas and only one decimal point.');
  392. if (!is_numeric($form_state['values']['weight']) && !preg_match($pattern, $form_state['values']['weight'])) {
  393. form_set_error('weight', $price_error);
  394. }
  395. }
  396. /**
  397. * Form submission handler for uc_attribute_option_form().
  398. *
  399. * @see uc_attribute_option_form()
  400. * @see uc_attribute_option_form_validate()
  401. */
  402. function uc_attribute_option_form_submit($form, &$form_state) {
  403. if (!isset($form_state['values']['oid'])) {
  404. drupal_write_record('uc_attribute_options', $form_state['values']);
  405. drupal_set_message(t('Created new option %option.', array('%option' => $form_state['values']['name'])));
  406. watchdog('uc_attribute', 'Created new option %option.', array('%option' => $form_state['values']['name']), WATCHDOG_NOTICE, 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options/add');
  407. $form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options/add';
  408. }
  409. else {
  410. drupal_write_record('uc_attribute_options', $form_state['values'], array('aid', 'oid'));
  411. drupal_set_message(t('Updated option %option.', array('%option' => $form_state['values']['name'])));
  412. watchdog('uc_attribute', 'Updated option %option.', array('%option' => $form_state['values']['name']), WATCHDOG_NOTICE, 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options/' . $form_state['values']['oid']);
  413. $form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options';
  414. }
  415. }
  416. /**
  417. * Confirms deletion of the given attribute option.
  418. *
  419. * @see uc_attribute_option_delete_confirm_submit()
  420. */
  421. function uc_attribute_option_delete_confirm($form, &$form_state, $attribute, $option) {
  422. if (empty($option)) {
  423. drupal_set_message(t('There is no option with that ID.'), 'error');
  424. drupal_goto('admin/store/products/attributes/' . $attribute->aid . '/options');
  425. }
  426. $aid = $attribute->aid;
  427. $oid = $option->oid;
  428. $form['aid'] = array('#type' => 'value', '#value' => $aid);
  429. $form['oid'] = array('#type' => 'value', '#value' => $oid);
  430. $output = confirm_form($form, t('Are you sure you want to delete the option %name?', array('%name' => $option->name)), 'admin/store/products/attributes/' . $aid . '/options', '', t('Delete'), t('Cancel'));
  431. return $output;
  432. }
  433. /**
  434. * Form submission handler for uc_attribute_option_delete_confirm().
  435. *
  436. * @see uc_attribute_option_delete_confirm()
  437. */
  438. function uc_attribute_option_delete_confirm_submit($form, &$form_state) {
  439. if ($form_state['values']['confirm']) {
  440. $match = 'i:' . $form_state['values']['aid'] . ';s:' . strlen($form_state['values']['oid']) . ':"' . $form_state['values']['oid'] . '";';
  441. db_delete('uc_product_adjustments')
  442. ->condition('combination', '%' . db_like($match) . '%', 'LIKE')
  443. ->execute();
  444. $select = db_select('uc_attribute_options', 'ao')
  445. ->where('{uc_class_attribute_options}.oid = ao.oid')
  446. ->condition('ao.oid', $form_state['values']['oid']);
  447. $select->addExpression('1');
  448. db_delete('uc_class_attribute_options')
  449. ->condition('', $select, 'EXISTS')
  450. ->execute();
  451. $select = db_select('uc_attribute_options', 'ao')
  452. ->where('{uc_product_options}.oid = ao.oid')
  453. ->condition('ao.oid', $form_state['values']['oid']);
  454. $select->addExpression('1');
  455. db_delete('uc_product_options')
  456. ->condition('', $select, 'EXISTS')
  457. ->execute();
  458. db_delete('uc_attribute_options')
  459. ->condition('oid', $form_state['values']['oid'])
  460. ->execute();
  461. }
  462. $form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options';
  463. }
  464. /**
  465. * Form to associate attributes with products or classes.
  466. *
  467. * @see uc_object_attributes_form_submit()
  468. * @see theme_uc_object_attributes_form()
  469. * @ingroup forms
  470. */
  471. function uc_object_attributes_form($form, &$form_state, $object, $type, $view = 'overview') {
  472. switch ($type) {
  473. case 'class':
  474. $class = $object;
  475. $id = $class->pcid;
  476. if (empty($class->name)) {
  477. drupal_goto('admin/store/products/classes/' . $id);
  478. }
  479. drupal_set_title($class->name);
  480. $attributes = uc_class_get_attributes($id);
  481. break;
  482. case 'product':
  483. default:
  484. $product = $object;
  485. $id = $product->nid;
  486. if (empty($product->title)) {
  487. drupal_goto('node/' . $id);
  488. }
  489. drupal_set_title($product->title);
  490. $attributes = uc_product_get_attributes($id);
  491. }
  492. $used_aids = array();
  493. foreach ($attributes as $attribute) {
  494. $used_aids[] = $attribute->aid;
  495. }
  496. if ($view == 'overview') {
  497. $form['#tree'] = TRUE;
  498. $form['attributes'] = array();
  499. if (count($attributes) > 0) {
  500. foreach ($attributes as $attribute) {
  501. $option = isset($attribute->options[$attribute->default_option]) ? $attribute->options[$attribute->default_option] : NULL;
  502. $form['attributes'][$attribute->aid] = array(
  503. 'remove' => array(
  504. '#type' => 'checkbox',
  505. '#title' => t('Remove'),
  506. '#title_display' => 'invisible',
  507. '#default_value' => 0,
  508. ),
  509. 'name' => array(
  510. '#markup' => check_plain($attribute->name),
  511. ),
  512. 'label' => array(
  513. '#type' => 'textfield',
  514. '#title' => t('Label'),
  515. '#title_display' => 'invisible',
  516. '#default_value' => empty($attribute->label) ? $attribute->name : $attribute->label,
  517. '#size' => 20,
  518. ),
  519. 'option' => array(
  520. '#markup' => $option ? (check_plain($option->name) . ' (' . theme('uc_price', array('price' => $option->price)) . ')' ) : t('n/a'),
  521. ),
  522. 'required' => array(
  523. '#type' => 'checkbox',
  524. '#title' => t('Required'),
  525. '#title_display' => 'invisible',
  526. '#default_value' => $attribute->required,
  527. ),
  528. 'ordering' => array(
  529. '#type' => 'weight',
  530. '#title' => t('List position'),
  531. '#title_display' => 'invisible',
  532. '#delta' => 25,
  533. '#default_value' => $attribute->ordering,
  534. '#attributes' => array('class' => array('uc-attribute-table-ordering')),
  535. ),
  536. 'display' => array(
  537. '#type' => 'select',
  538. '#title' => t('Display'),
  539. '#title_display' => 'invisible',
  540. '#default_value' => $attribute->display,
  541. '#options' => _uc_attribute_display_types(),
  542. ),
  543. );
  544. }
  545. $form['actions'] = array('#type' => 'actions');
  546. $form['actions']['save'] = array(
  547. '#type' => 'submit',
  548. '#value' => t('Save changes'),
  549. '#weight' => -2,
  550. );
  551. }
  552. }
  553. elseif ($view == 'add') {
  554. // Get list of attributes not already assigned to this node or class.
  555. $unused_attributes = array();
  556. $result = db_query("SELECT a.aid, a.name, a.label FROM {uc_attributes} a LEFT JOIN {uc_attribute_options} ao ON a.aid = ao.aid GROUP BY a.aid, a.name, a.label ORDER BY a.name");
  557. foreach ($result as $attribute) {
  558. if (!in_array($attribute->aid, $used_aids)) {
  559. $unused_attributes[$attribute->aid] = $attribute->name;
  560. }
  561. }
  562. $form['add_attributes'] = array(
  563. '#type' => 'checkboxes',
  564. '#title' => t('Attributes'),
  565. '#options' => count($unused_attributes) > 0 ? $unused_attributes : array(t('No attributes left to add.')),
  566. '#disabled' => count($unused_attributes) == 0 ? TRUE : FALSE,
  567. '#weight' => -1
  568. );
  569. $form['actions'] = array('#type' => 'actions');
  570. $form['actions']['add'] = array(
  571. '#type' => 'submit',
  572. '#value' => t('Add attributes'),
  573. '#suffix' => l(t('Cancel'), $type == 'product' ? 'node/' . $id . '/edit/attributes' : 'admin/store/products/classes/' . $class->pcid . '/attributes'),
  574. '#weight' => 0,
  575. );
  576. }
  577. $form['id'] = array(
  578. '#type' => 'value',
  579. '#value' => $id,
  580. );
  581. $form['type'] = array(
  582. '#type' => 'value',
  583. '#value' => $type,
  584. );
  585. $form['view'] = array(
  586. '#type' => 'value',
  587. '#value' => $view,
  588. );
  589. return $form;
  590. }
  591. /**
  592. * Displays the formatted attribute form.
  593. *
  594. * @param $variables
  595. * An associative array containing:
  596. * - form: A render element representing the form.
  597. *
  598. * @see uc_object_attributes_form()
  599. * @ingroup themeable
  600. */
  601. function theme_uc_object_attributes_form($variables) {
  602. $form = $variables['form'];
  603. $output = '';
  604. if ($form['view']['#value'] == 'overview') {
  605. $header = array(t('Remove'), t('Name'), t('Label'), t('Default'), t('Required'), t('List position'), t('Display'));
  606. $rows = array();
  607. foreach (element_children($form['attributes']) as $aid) {
  608. $rows[] = array(
  609. 'data' => array(
  610. drupal_render($form['attributes'][$aid]['remove']),
  611. drupal_render($form['attributes'][$aid]['name']),
  612. drupal_render($form['attributes'][$aid]['label']),
  613. drupal_render($form['attributes'][$aid]['option']),
  614. drupal_render($form['attributes'][$aid]['required']),
  615. drupal_render($form['attributes'][$aid]['ordering']),
  616. drupal_render($form['attributes'][$aid]['display']),
  617. ),
  618. 'class' => array('draggable'),
  619. );
  620. }
  621. drupal_add_tabledrag('uc-attribute-table', 'order', 'sibling', 'uc-attribute-table-ordering');
  622. if ($form['type']['#value'] == 'class') {
  623. $path = url('admin/store/products/classes/' . $form['id']['#value'] . '/attributes/add');
  624. }
  625. elseif ($form['type']['#value'] == 'product') {
  626. $path = url('node/' . $form['id']['#value'] . '/edit/attributes/add');
  627. }
  628. $output = theme('table', array(
  629. 'header' => $header,
  630. 'rows' => $rows,
  631. 'attributes' => array('id' => 'uc-attribute-table'),
  632. 'empty' => t('You must first <a href="!url">add attributes to this !type</a>.', array('!url' => $path, '!type' => $form['type']['#value'])),
  633. ));
  634. }
  635. else {
  636. $output = '<div class="uc-attributes-add-link">';
  637. $output .= t('You may add more attributes <a href="!url">here</a>.', array('!url' => url('admin/store/products/attributes/add')));
  638. $output .= '</div>';
  639. }
  640. $output .= drupal_render_children($form);
  641. return $output;
  642. }
  643. /**
  644. * Form submission handler for uc_object_attributes_form().
  645. *
  646. * @see uc_object_attributes_form()
  647. */
  648. function uc_object_attributes_form_submit($form, &$form_state) {
  649. if ($form_state['values']['type'] == 'product') {
  650. $attr_table = 'uc_product_attributes';
  651. $opt_table = 'uc_product_options';
  652. $id = 'nid';
  653. }
  654. elseif ($form_state['values']['type'] == 'class') {
  655. $attr_table = 'uc_class_attributes';
  656. $opt_table = 'uc_class_attribute_options';
  657. $id = 'pcid';
  658. }
  659. if ($form_state['values']['view'] == 'overview' && is_array($form_state['values']['attributes'])) {
  660. $changed = FALSE;
  661. foreach ($form_state['values']['attributes'] as $aid => $attribute) {
  662. if ($attribute['remove']) {
  663. $remove_aids[] = $aid;
  664. }
  665. else {
  666. $attribute['aid'] = $aid;
  667. $attribute[$id] = $form_state['values']['id'];
  668. drupal_write_record($attr_table, $attribute, array('aid', $id));
  669. $changed = TRUE;
  670. }
  671. }
  672. if (isset($remove_aids)) {
  673. $id_value = $form_state['values']['id'];
  674. $select = db_select('uc_attribute_options', 'ao')
  675. ->fields('ao', array('oid'))
  676. ->condition('ao.aid', $remove_aids, 'IN');
  677. db_delete($opt_table)
  678. ->condition('oid', $select, 'IN')
  679. ->condition($id, $id_value)
  680. ->execute();
  681. db_delete($attr_table)
  682. ->condition($id, $id_value)
  683. ->condition('aid', $remove_aids, 'IN')
  684. ->execute();
  685. if ($form_state['values']['type'] == 'product') {
  686. db_delete('uc_product_adjustments')
  687. ->condition('nid', $id_value)
  688. ->execute();
  689. }
  690. drupal_set_message(format_plural(count($remove_aids), '1 attribute has been removed.', '@count attributes have been removed.'));
  691. }
  692. if ($changed) {
  693. drupal_set_message(t('The changes have been saved.'));
  694. }
  695. }
  696. elseif ($form_state['values']['view'] == 'add') {
  697. foreach (array_filter($form_state['values']['add_attributes']) as $aid) {
  698. // Enable all options for added attributes.
  699. $attribute = uc_attribute_load($aid);
  700. $oid = 0;
  701. if (isset($attribute->options)) {
  702. foreach ($attribute->options as $option) {
  703. $option->$id = $form_state['values']['id'];
  704. drupal_write_record($opt_table, $option);
  705. $option->aid = $aid;
  706. }
  707. // Make the first option (if any) the default.
  708. if ($option = reset($attribute->options)) {
  709. $oid = $option->oid;
  710. }
  711. }
  712. $select = db_select('uc_attributes', 'a')
  713. ->condition('aid', $aid);
  714. $select->addExpression(':id', $id, array(':id' => $form_state['values']['id']));
  715. $select->addField('a', 'aid');
  716. $select->addField('a', 'label');
  717. $select->addField('a', 'ordering');
  718. $select->addExpression(':oid', 'default_option', array(':oid' => $oid));
  719. $select->addField('a', 'required');
  720. $select->addField('a', 'display');
  721. db_insert($attr_table)
  722. ->from($select)
  723. ->execute();
  724. }
  725. $num = count(array_filter($form_state['values']['add_attributes']));
  726. if ($num > 0) {
  727. if ($form_state['values']['type'] == 'product') {
  728. db_delete('uc_product_adjustments')
  729. ->condition('nid', $form_state['values']['id'])
  730. ->execute();
  731. }
  732. drupal_set_message(format_plural($num, '1 attribute has been added.', '@count attributes have been added.'));
  733. }
  734. }
  735. if ($form_state['values']['type'] == 'product') {
  736. if (module_exists('entitycache')) {
  737. cache_clear_all($form_state['values']['id'], 'cache_entity_node');
  738. }
  739. $form_state['redirect'] = 'node/' . $form_state['values']['id'] . '/edit/attributes';
  740. }
  741. else {
  742. $form_state['redirect'] = 'admin/store/products/classes/' . $form_state['values']['id'] . '/attributes';
  743. }
  744. }
  745. /**
  746. * Form to assign and modify attribute options on products or classes.
  747. *
  748. * @see uc_object_options_form_validate()
  749. * @see uc_object_options_form_submit()
  750. * @see theme_uc_object_options_form()
  751. * @ingroup forms
  752. */
  753. function uc_object_options_form($form, &$form_state, $object, $type) {
  754. if ($type == 'product') {
  755. $product = $object;
  756. $id = $product->nid;
  757. drupal_set_title($product->title);
  758. $attributes = uc_product_get_attributes($id);
  759. $table = 'uc_product_options';
  760. $id_type = 'nid';
  761. }
  762. elseif ($type == 'class') {
  763. $class = $object;
  764. $id = $class->pcid;
  765. drupal_set_title($class->name);
  766. $attributes = uc_class_get_attributes($id);
  767. $table = 'uc_class_attribute_options';
  768. $id_type = 'pcid';
  769. }
  770. foreach ($attributes as $aid => $attribute) {
  771. $form['attributes'][$aid]['name'] = array(
  772. '#markup' => check_plain($attribute->name),
  773. );
  774. $form['attributes'][$aid]['aid'] = array(
  775. '#type' => 'hidden',
  776. '#value' => $attribute->aid,
  777. );
  778. $form['attributes'][$aid]['ordering'] = array(
  779. '#type' => 'value',
  780. '#value' => $attribute->ordering,
  781. );
  782. $form['attributes'][$aid]['options'] = array('#weight' => 2);
  783. $base_attr = uc_attribute_load($attribute->aid);
  784. if ($base_attr->options) {
  785. $options = array();
  786. $query = db_select('uc_attribute_options', 'ao')
  787. ->fields('ao', array(
  788. 'aid',
  789. 'oid',
  790. 'name',
  791. ));
  792. $query->leftJoin($table, 'po', "ao.oid = po.oid AND po.$id_type = :id", array(':id' => $id));
  793. $query->addField('ao', 'cost', 'default_cost');
  794. $query->addField('ao', 'price', 'default_price');
  795. $query->addField('ao', 'weight', 'default_weight');
  796. $query->addField('ao', 'ordering', 'default_ordering');
  797. $query->fields('po', array(
  798. 'cost',
  799. 'price',
  800. 'weight',
  801. 'ordering',
  802. ))
  803. ->addExpression('CASE WHEN po.ordering IS NULL THEN 1 ELSE 0 END', 'null_order');
  804. $query->condition('aid', $attribute->aid)
  805. ->orderBy('null_order')
  806. ->orderBy('po.ordering')
  807. ->orderBy('default_ordering')
  808. ->orderBy('ao.name');
  809. $result = $query->execute();
  810. foreach ($result as $option) {
  811. $oid = $option->oid;
  812. $options[$oid] = '';
  813. $form['attributes'][$aid]['options'][$oid]['select'] = array(
  814. '#type' => 'checkbox',
  815. '#default_value' => isset($attribute->options[$oid]) ? TRUE : FALSE,
  816. '#title' => check_plain($option->name),
  817. );
  818. $form['attributes'][$aid]['options'][$oid]['cost'] = array(
  819. '#type' => 'uc_price',
  820. '#title' => t('Cost'),
  821. '#title_display' => 'invisible',
  822. '#default_value' => is_null($option->cost) ? $option->default_cost : $option->cost,
  823. '#size' => 6,
  824. '#allow_negative' => TRUE,
  825. );
  826. $form['attributes'][$aid]['options'][$oid]['price'] = array(
  827. '#type' => 'uc_price',
  828. '#title' => t('Price'),
  829. '#title_display' => 'invisible',
  830. '#default_value' => is_null($option->price) ? $option->default_price : $option->price,
  831. '#size' => 6,
  832. '#allow_negative' => TRUE,
  833. );
  834. $form['attributes'][$aid]['options'][$oid]['weight'] = array(
  835. '#type' => 'textfield',
  836. '#title' => t('Weight'),
  837. '#title_display' => 'invisible',
  838. '#default_value' => is_null($option->weight) ? $option->default_weight : $option->weight,
  839. '#size' => 5,
  840. );
  841. $form['attributes'][$aid]['options'][$oid]['ordering'] = array(
  842. '#type' => 'weight',
  843. '#title' => t('List position'),
  844. '#title_display' => 'invisible',
  845. '#delta' => 50,
  846. '#default_value' => is_null($option->ordering) ? $option->default_ordering : $option->ordering,
  847. '#attributes' => array('class' => array('uc-attribute-option-table-ordering')),
  848. );
  849. }
  850. $form['attributes'][$aid]['default'] = array(
  851. '#type' => 'radios',
  852. '#title' => t('Default'),
  853. '#title_display' => 'invisible',
  854. '#options' => $options,
  855. '#default_value' => $attribute->default_option,
  856. );
  857. }
  858. }
  859. if (!empty($form['attributes'])) {
  860. $form['attributes']['#tree'] = TRUE;
  861. $form['actions'] = array('#type' => 'actions');
  862. $form['actions']['submit'] = array(
  863. '#type' => 'submit',
  864. '#value' => t('Submit'),
  865. '#weight' => 10,
  866. );
  867. }
  868. $form['id'] = array(
  869. '#type' => 'value',
  870. '#value' => $id,
  871. );
  872. $form['type'] = array(
  873. '#type' => 'value',
  874. '#value' => $type,
  875. );
  876. return $form;
  877. }
  878. /**
  879. * Displays the option form.
  880. *
  881. * @param $variables
  882. * An associative array containing:
  883. * - form: A render element representing the form.
  884. *
  885. * @see uc_object_options_form()
  886. * @ingroup themeable
  887. */
  888. function theme_uc_object_options_form($variables) {
  889. $form = $variables['form'];
  890. $output = '';
  891. drupal_add_js('misc/tableselect.js');
  892. $header = array(array('data' => '&nbsp;&nbsp;' . t('Options'), 'class' => array('select-all')), t('Default'), t('Cost'), t('Price'), t('Weight'), t('List position'));
  893. $tables = 0;
  894. if (isset($form['attributes'])) {
  895. foreach (element_children($form['attributes']) as $key) {
  896. $rows = array();
  897. foreach (element_children($form['attributes'][$key]['options']) as $oid) {
  898. $rows[] = array(
  899. 'data' => array(
  900. drupal_render($form['attributes'][$key]['options'][$oid]['select']),
  901. drupal_render($form['attributes'][$key]['default'][$oid]),
  902. drupal_render($form['attributes'][$key]['options'][$oid]['cost']),
  903. drupal_render($form['attributes'][$key]['options'][$oid]['price']),
  904. drupal_render($form['attributes'][$key]['options'][$oid]['weight']),
  905. drupal_render($form['attributes'][$key]['options'][$oid]['ordering']),
  906. ),
  907. 'class' => array('draggable'),
  908. );
  909. }
  910. $table_id = 'uc-attribute-option-table-' . $tables++;
  911. drupal_add_tabledrag($table_id, 'order', 'sibling', 'uc-attribute-option-table-ordering');
  912. $output .= theme('table', array(
  913. 'header' => $header,
  914. 'rows' => $rows,
  915. 'attributes' => array(
  916. 'class' => array('product_attributes'),
  917. 'id' => $table_id,
  918. ),
  919. 'caption' => '<h2>' . drupal_render($form['attributes'][$key]['name']) . '</h2>',
  920. 'empty' => t('This attribute does not have any options.'),
  921. ));
  922. }
  923. }
  924. if (!$tables) {
  925. if ($form['type']['#value'] == 'product') {
  926. drupal_set_message(t('This product does not have any attributes.'), 'warning');
  927. }
  928. else {
  929. drupal_set_message(t('This product class does not have any attributes.'), 'warning');
  930. }
  931. }
  932. $output .= drupal_render_children($form);
  933. return $output;
  934. }
  935. /**
  936. * Returns a themed set of attribute options for use in order displays.
  937. *
  938. * @param $variables
  939. * An associative array containing:
  940. * - attributes: An associative array containing the set of attributes,
  941. * with each element keyed by attribute ID:
  942. * - <aid>: An associative array containing:
  943. * - #attribute_name: Attribute name.
  944. * - #options: Array of option names.
  945. *
  946. * @return
  947. * Themed set of attribute options.
  948. *
  949. * @ingroup themeable
  950. */
  951. function theme_uc_product_attributes($variables) {
  952. $attributes = $variables['attributes'];
  953. $option_rows = array();
  954. foreach (element_children($attributes) as $key) {
  955. $optionstr = '';
  956. foreach ((array)$attributes[$key]['#options'] as $option) {
  957. // We only need to allow translation from the second option onward
  958. if (empty($optionstr)) {
  959. $optionstr .= $option;
  960. }
  961. else {
  962. $optionstr .= t(', !option', array('!option' => $option));
  963. }
  964. }
  965. if ($optionstr != '') {
  966. $option_rows[$key] = t('@attribute: @option', array('@attribute' => $attributes[$key]['#attribute_name'], '@option' => $optionstr));
  967. }
  968. }
  969. if (!empty($option_rows)) {
  970. return theme('item_list', array('items' => array_values($option_rows), 'attributes' => array('class' => array('product-description'))));
  971. }
  972. return '';
  973. }
  974. /**
  975. * Makes sure that all selected default options are enabled.
  976. *
  977. * @see uc_object_options_form()
  978. * @see uc_object_options_form_submit()
  979. */
  980. function uc_object_options_form_validate($form, &$form_state) {
  981. $error = FALSE;
  982. if (isset($form_state['values']['attributes'])) {
  983. foreach ($form_state['values']['attributes'] as $aid => $attribute) {
  984. $selected_opts = array();
  985. if (isset($attribute['options'])) {
  986. foreach ($attribute['options'] as $oid => $option) {
  987. if ($option['select'] == 1) {
  988. $selected_opts[] = $oid;
  989. }
  990. }
  991. }
  992. if (!empty($selected_opts) && !isset($form['attributes'][$aid]['default']['#disabled']) && !in_array($attribute['default'], $selected_opts)) {
  993. form_set_error($attribute['default']);
  994. $error = TRUE;
  995. }
  996. }
  997. }
  998. if ($error) {
  999. drupal_set_message(t('All attributes with enabled options must specify an enabled option as default.'), 'error');
  1000. }
  1001. }
  1002. /**
  1003. * Form submission handler for uc_object_options_form().
  1004. *
  1005. * @see uc_object_options_form()
  1006. * @see uc_object_options_form_validate()
  1007. */
  1008. function uc_object_options_form_submit($form, &$form_state) {
  1009. if ($form_state['values']['type'] == 'product') {
  1010. $attr_table = 'uc_product_attributes';
  1011. $opt_table = 'uc_product_options';
  1012. $id = 'nid';
  1013. }
  1014. elseif ($form_state['values']['type'] == 'class') {
  1015. $attr_table = 'uc_class_attributes';
  1016. $opt_table = 'uc_class_attribute_options';
  1017. $id = 'pcid';
  1018. }
  1019. foreach ($form_state['values']['attributes'] as $attribute) {
  1020. if (isset($attribute['default'])) {
  1021. db_update($attr_table)
  1022. ->fields(array(
  1023. 'default_option' => $attribute['default'],
  1024. ))
  1025. ->condition($id, $form_state['values']['id'])
  1026. ->condition('aid', $attribute['aid'])
  1027. ->execute();
  1028. }
  1029. if (isset($attribute['options'])) {
  1030. db_delete($opt_table)
  1031. ->condition($id, $form_state['values']['id'])
  1032. ->condition('oid', array_keys($attribute['options']), 'IN')
  1033. ->execute();
  1034. foreach ($attribute['options'] as $oid => $option) {
  1035. if ($option['select']) {
  1036. $option[$id] = $form_state['values']['id'];
  1037. $option['oid'] = $oid;
  1038. drupal_write_record($opt_table, $option);
  1039. }
  1040. elseif ($form_state['values']['type'] == 'product') {
  1041. $aid = $attribute['aid'];
  1042. $match = 'i:' . $aid . ';s:' . strlen($oid) . ':"' . $oid . '";';
  1043. db_delete('uc_product_adjustments')
  1044. ->condition('nid', $form_state['values']['id'])
  1045. ->condition('combination', '%' . db_like($match) . '%', 'LIKE')
  1046. ->execute();
  1047. }
  1048. }
  1049. }
  1050. }
  1051. drupal_set_message(t('The @type options have been saved.', array('@type' => $form_state['values']['type'] == 'product' ? t('product') : t('product class'))));
  1052. if ($form_state['values']['type'] == 'product') {
  1053. // Clear the page and block caches.
  1054. cache_clear_all();
  1055. }
  1056. }
  1057. /**
  1058. * Form builder: associate option combinations with a product variant's SKU.
  1059. *
  1060. * @see uc_product_adjustments_form_submit()
  1061. * @ingroup forms
  1062. */
  1063. function uc_product_adjustments_form($form, &$form_state, $node) {
  1064. drupal_set_title($node->title);
  1065. $nid = $node->nid;
  1066. // Populate table and such.
  1067. $model = $node->model;
  1068. $query = db_select('uc_product_attributes', 'pa');
  1069. $query->leftJoin('uc_attributes', 'a', 'pa.aid = a.aid');
  1070. $query->leftJoin('uc_attribute_options', 'ao', 'a.aid = ao.aid');
  1071. $query->leftJoin('uc_product_options', 'po', 'ao.oid = po.oid AND po.nid = :po_nid', array(':po_nid' => $nid));
  1072. $result = $query->fields('pa', array('nid', 'aid', 'ordering', 'display'))
  1073. ->fields('a', array('name', 'ordering', 'aid'))
  1074. ->fields('ao', array('aid'))
  1075. ->condition('pa.nid', $nid)
  1076. ->having('COUNT(po.oid) > 0')
  1077. ->groupBy('ao.aid')
  1078. ->groupBy('pa.aid')
  1079. ->groupBy('pa.display')
  1080. ->groupBy('a.name')
  1081. ->groupBy('pa.ordering')
  1082. ->groupBy('a.ordering')
  1083. ->groupBy('pa.nid')
  1084. ->addTag('uc_product_adjustments_form')
  1085. ->execute();
  1086. $i = 1;
  1087. $attribute_names = '';
  1088. $full_attributes = array();
  1089. $values = array();
  1090. $query = db_select('uc_product_options', "po$i")->extend('PagerDefault')
  1091. ->limit(20);
  1092. $attribute_ids = array();
  1093. foreach ($result as $prod_attr) {
  1094. if ($i > 1) {
  1095. $query->join('uc_product_options', "po$i");
  1096. }
  1097. $query->leftJoin('uc_attribute_options', "ao$i", "po$i.oid = ao$i.oid AND po$i.nid = :nid", array(':nid' => $nid));
  1098. $query->addField("ao$i", 'aid', "aid$i");
  1099. $query->addField("ao$i", 'name', "name$i");
  1100. $query->addField("ao$i", 'oid', "oid$i");
  1101. $query->addField("po$i", 'ordering', "ordering$i");
  1102. $query->condition("ao$i.aid", $prod_attr->aid)
  1103. ->orderBy("po$i.ordering")
  1104. ->orderBy("ao$i.name");
  1105. ++$i;
  1106. $attribute_names .= '<th>' . check_plain($prod_attr->name) . '</th>';
  1107. $attribute_ids[] = $prod_attr->aid;
  1108. }
  1109. $num_prod_attr = count($attribute_ids);
  1110. if ($num_prod_attr) {
  1111. // Get previous values
  1112. $old_vals = db_query("SELECT * FROM {uc_product_adjustments} WHERE nid = :nid", array(':nid' => $nid))->fetchAll();
  1113. $result = $query->execute();
  1114. $form['original'] = array(
  1115. '#markup' => '<p><b>' . t('Default product SKU: @sku', array('@sku' => $model)) . '</b></p>',
  1116. );
  1117. $form['default'] = array(
  1118. '#type' => 'value',
  1119. '#value' => $model,
  1120. );
  1121. $form['table'] = array(
  1122. '#prefix' => '<table class="combinations">',
  1123. '#suffix' => '</table>',
  1124. );
  1125. $form['table']['head'] = array(
  1126. '#markup' => '<thead><tr>' . $attribute_names . '<th>' . t('Alternate SKU') . '</th></tr></thead>',
  1127. '#weight' => 0,
  1128. );
  1129. $form['table']['body'] = array(
  1130. '#prefix' => '<tbody>',
  1131. '#suffix' => '</tbody>',
  1132. '#weight' => 1,
  1133. '#tree' => TRUE,
  1134. );
  1135. $i = 0;
  1136. while ($combo = $result->fetchObject()) {
  1137. $cells = '';
  1138. $row_title = '';
  1139. $comb_array = array();
  1140. for ($j = 1; $j <= $num_prod_attr; ++$j) {
  1141. $cells .= '<td>' . check_plain($combo->{'name' . $j}) . '</td>';
  1142. $row_title .= check_plain($combo->{'name' . $j}) . ', ';
  1143. $comb_array[$combo->{'aid' . $j}] = $combo->{'oid' . $j};
  1144. }
  1145. ksort($comb_array);
  1146. $row_title = substr($row_title, 0, strlen($row_title) - 2);
  1147. $default_model = $model;
  1148. foreach ($old_vals as $ov) {
  1149. if ($ov->combination == serialize($comb_array)) {
  1150. $default_model = $ov->model;
  1151. break;
  1152. }
  1153. }
  1154. $form['table']['body'][$i] = array(
  1155. '#prefix' => '<tr title="' . $row_title . '">',
  1156. '#suffix' => '</tr>',
  1157. );
  1158. $form['table']['body'][$i]['combo'] = array(
  1159. '#markup' => $cells,
  1160. );
  1161. $form['table']['body'][$i]['combo_array'] = array(
  1162. '#type' => 'value',
  1163. '#value' => serialize($comb_array),
  1164. );
  1165. $form['table']['body'][$i]['model'] = array(
  1166. '#type' => 'textfield',
  1167. '#default_value' => $default_model,
  1168. '#prefix' => '<td>',
  1169. '#suffix' => '</td>',
  1170. );
  1171. ++$i;
  1172. }
  1173. $form['nid'] = array(
  1174. '#type' => 'hidden',
  1175. '#value' => $nid,
  1176. );
  1177. $form['actions'] = array('#type' => 'actions');
  1178. $form['actions']['submit'] = array(
  1179. '#type' => 'submit',
  1180. '#value' => t('Submit'),
  1181. );
  1182. }
  1183. else {
  1184. $form['error'] = array(
  1185. '#markup' => '<div><br />' . t('This product does not have any attributes that can be used for SKU adjustments.') . '</div>',
  1186. );
  1187. }
  1188. $form['pager'] = array(
  1189. '#theme' => 'pager',
  1190. );
  1191. return $form;
  1192. }
  1193. /**
  1194. * Form builder for uc_product_adjustments_form().
  1195. *
  1196. * @see uc_product_adjustments_form()
  1197. */
  1198. function uc_product_adjustments_form_submit($form, &$form_state) {
  1199. foreach ($form_state['values']['body'] as $value) {
  1200. if (!empty($value['model']) && $value['model'] != $form_state['values']['default']) {
  1201. db_merge('uc_product_adjustments')
  1202. ->key(array(
  1203. 'nid' => $form_state['values']['nid'],
  1204. 'combination' => $value['combo_array'],
  1205. ))
  1206. ->fields(array(
  1207. 'model' => $value['model'],
  1208. ))
  1209. ->execute();
  1210. }
  1211. else {
  1212. db_delete('uc_product_adjustments')
  1213. ->condition('nid', $form_state['values']['nid'])
  1214. ->condition('combination', $value['combo_array'])
  1215. ->execute();
  1216. }
  1217. }
  1218. drupal_set_message(t('Product adjustments have been saved.'));
  1219. }