function commerce_square_payment_method_submit_form_validate in Commerce Square Connect 7
Square payment checkout pane validate callback.
File
- ./
commerce_square.module, line 472 - Module file for Commerce Square.
Code
function commerce_square_payment_method_submit_form_validate($payment_method, $pane_form, $pane_values, $order) {
if (empty($pane_values['payment_method_nonce'])) {
drupal_set_message('There was an error collecting the payment information.', 'error');
return FALSE;
}
libraries_load('square');
$mode = $payment_method['settings']['mode'];
$location_id = $payment_method['settings'][$mode . '_location_id'];
$charge = commerce_payment_order_balance($order);
$square_total_amount = $charge['amount'];
$square_order_currency = $charge['currency_code'];
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$square_api = SquareApi::createFromInstanceId($payment_method['instance_id']);
$api_client = $square_api
->getClient();
$order_api_instance = new OrdersApi($api_client);
$charge_api_instance = new TransactionsApi($api_client);
// Containers for accumulating line item data
$line_items = array();
$square_line_item_total = 0;
// Iterate through Drupal Commerce standard line items
foreach ($order_wrapper->commerce_line_items as $line_item_wrapper) {
$line_item = new OrderLineItem();
$base_price_money = new Money();
$base_price_money
->setAmount((int) $line_item_wrapper->commerce_unit_price->amount
->value());
$base_price_money
->setCurrency($line_item_wrapper->commerce_unit_price->currency_code
->value());
$line_item
->setBasePriceMoney($base_price_money);
$line_item_label = $line_item_wrapper->line_item_label
->value();
// Convert line item label to product title + (SKU).
if (isset($line_item_wrapper->commerce_product)) {
$line_item_label = $line_item_wrapper->commerce_product->title
->value() . ' (' . $line_item_wrapper->commerce_product->sku
->value() . ')';
}
$line_item
->setName($line_item_label);
// Quantity needs to be a string integer, it cannot be a float.
$line_item
->setQuantity((string) (int) $line_item_wrapper->quantity
->value());
// Handling DISCOUNTS and VAT:
// If either are included in line item price, include details in Note field.
// Note that we are NOT adding them as Square discount/tax elements because of
// limitations in Square's discount/tax calculation flexibility and to avoid any
// discrepancies in totals between Drupal and Square.
$line_item_price_data_array = $line_item_wrapper->commerce_unit_price->data
->value();
$line_item_price_components = $line_item_price_data_array['components'];
if (count($line_item_price_components) > 1) {
$price_component_notes = array();
foreach ($line_item_price_components as $price) {
// Skip base_price component and components that are not included as
// part of the price (ie, VAT.)
if ($price['name'] === 'base_price' || $price['included'] === FALSE) {
continue;
}
$formatted_component_price = commerce_currency_format($price['price']['amount'], $price['price']['currency_code']);
$component_label = $price['name'];
// If the price component is from the commerce_discount module and
// provides a component title, use that.
if (isset($price['price']['data']['discount_component_title'])) {
$component_label = $price['price']['data']['discount_component_title'];
}
elseif ($price['name'] === 'discount') {
$component_label = t('Sale');
}
elseif (isset($price['price']['data']['tax_rate']['display_title'])) {
$component_label = $price['price']['data']['tax_rate']['display_title'];
}
$price_component_notes[] = $component_label . ' ' . $formatted_component_price;
}
// Format Note if there was at least one component to be displayed.
if (count($price_component_notes) > 0) {
$adjust_text = format_plural(count($price_component_notes), 'Adjustment', 'Adjustments');
$include_text = t('included in price (per item):');
$notes_text = implode('; ', $price_component_notes);
$line_item
->setNote($adjust_text . ' ' . $include_text . ' ' . $notes_text);
}
}
$line_items[] = $line_item;
$square_line_item_total += $line_item_wrapper->commerce_total->amount
->value();
}
// ONLY IF commerce_tax is installed & enabled:
// Add order-level taxes (EXCLUDED from line item price) as generic line items,
// ignoring Square's tax functionality to avoid discrepancies in calculations and rounding.
// Note: if any other tax module is being used, it will NOT be added as a line item here,
// but will be handled with the catch-all final "adjustments"
if (module_exists('commerce_tax')) {
$order_total_data_array = $order_wrapper->commerce_order_total->data
->value();
$order_taxes = commerce_tax_components($order_total_data_array['components']);
foreach ($order_taxes as $tax) {
if ($tax['included'] === TRUE) {
continue;
}
$tax_money = new Money();
$tax_money
->setAmount((int) $tax['price']['amount']);
$tax_money
->setCurrency($tax['price']['currency_code']);
$line_item = new OrderLineItem();
$line_item
->setBasePriceMoney($tax_money);
$line_item
->setName($tax['price']['data']['tax_rate']['display_title']);
$line_item
->setQuantity('1');
// Done building line item. Add it to line items array.
$line_items[] = $line_item;
// Add line item total to running order total
$square_line_item_total += $tax['price']['amount'];
}
}
// Square requires the order total to match the payment amount, the following
// logic accommodates for rounding error or other omitted calculations.
if ($square_line_item_total != $square_total_amount) {
$diff = $square_total_amount - $square_line_item_total;
$total_money = new Money();
$total_money
->setAmount($diff);
$total_money
->setCurrency($square_order_currency);
$line_item = new OrderLineItem();
$line_item
->setBasePriceMoney($total_money);
$line_item
->setName(t('Adjustment'));
$line_item
->setQuantity('1');
$line_items[] = $line_item;
}
// Start building the Square Order.
$order_request = new CreateOrderRequest();
$order_request
->setIdempotencyKey(uniqid($order->order_id . '-', TRUE));
$order_request
->setReferenceId($order->order_id);
$order_request
->setLineItems($line_items);
// Make the Order API call
try {
$order_result = $order_api_instance
->createOrder($location_id, $order_request);
} catch (ApiException $e) {
$response = $e
->getResponseBody();
$error = $response->errors[0];
drupal_set_message($error->detail, 'error');
$vars = array(
'@category' => $error->category,
'@code' => $error->code,
'@detail' => $error->detail,
);
watchdog('commerce_square', 'Square order error. category: @category code: @code detail: @detail', $vars);
return FALSE;
}
//// Above is all processing needed to prepare Order & get Square Order ID
//// Below we process the ChargeRequest
$charge_amount = new Money();
$charge_amount
->setAmount((int) $charge['amount']);
$charge_amount
->setCurrency($charge['currency_code']);
$charge_request = new IntegrationChargeRequest();
// Link the transaction to this order.
$charge_request
->setOrderId($order_result
->getOrder()
->getId());
$charge_request
->setAmountMoney($charge_amount);
$charge_request
->setDelayCapture($payment_method['settings']['type'] == COMMERCE_CREDIT_AUTH_ONLY);
$charge_request
->setCardNonce($pane_values['payment_method_nonce']);
$charge_request
->setIdempotencyKey(uniqid('', TRUE));
$charge_request
->setBuyerEmailAddress($order->mail);
// The Square note field identifies transactions in the Square dashboard.
// TODO: make site-configurable using tokens
$charge_label = t('Order #@order_number, @store', array(
'@order_number' => $order->order_id,
'@store' => variable_get('site_name'),
));
// Trim to max 60 characters (Square limit on field).
$charge_label = substr($charge_label, 0, 60);
$charge_request
->setNote($charge_label);
// The `integration_id` is only valid when live.
if ($mode === 'live') {
$charge_request
->setIntegrationId('sqi_b6ff0cd7acc14f7ab24200041d066ba6');
}
try {
$result = $charge_api_instance
->charge($location_id, $charge_request);
$order->square_result = $result;
} catch (ApiException $e) {
$response = $e
->getResponseBody();
$error = $response->errors[0];
drupal_set_message($error->detail, 'error');
$vars = array(
'@category' => $error->category,
'@code' => $error->code,
'@detail' => $error->detail,
);
watchdog('commerce_square', 'Square transaction error. category: @category code: @code detail: @detail', $vars);
return FALSE;
}
return TRUE;
}