class pm_square_checkout {
public $id = __CLASS__;
public $name = 'Square Checkout';
public $description = '';
public $author = 'Mishael Ochu';
public $version = '1.0';
public $website = 'https://www.squareup.com/';
public $priority = 0;
public function options($items, $subtotal, $tax, $currency_code, $customer) {
// If not enabled
if (empty($this->settings['status'])) return;
// If not in geo zone
if (!empty($this->settings['geo_zone_id'])) {
if (!reference::country($customer['country_code'])->in_geo_zone($customer['zone_code'], $this->settings['geo_zone_id'])) return;
}
$forbidden_items = $this-> settings['forbidden_items'];
if (!empty($forbidden_items)) {
foreach ($items as $item) {
$product_id = $item['product_id'];
$result = array_search(strval($product_id), $forbidden_items);
if (!is_bool($result)) {
$log_message = '['. date('Y-m-d H:i:s e').'] product is **forbidden**: ' . json_encode($item['name']) . PHP_EOL . PHP_EOL;
file_put_contents(FS_DIR_STORAGE . 'logs/debug.log', $log_message, FILE_APPEND);
return;
} else {
}
}
}
$forbidden_options = $this-> settings['forbidden_options'];
if (!empty($forbidden_options)) {
$forbidden_option_names = array();
foreach ($forbidden_options as $forbidden_option) {
$forbidden_attribute_group = new ent_attribute_group($forbidden_option);
$selected_language_code = language::$selected['code'];
$forbidden_option_name = $forbidden_attribute_group->data['name'][$selected_language_code];
array_push($forbidden_option_names, $forbidden_option_name);
}
foreach ($items as $item) {
$options = $item['options'];
if (!empty($options)) {
$item_option_names = array_keys($options);
if (!empty($item_option_names)) {
foreach ($item_option_names as $item_option_name) {
$result = array_search($item_option_name, $forbidden_option_names);
if (!is_bool($result)) {
$log_message = '['. date('Y-m-d H:i:s e').'] option is **forbidden**: ' . json_encode($item['name']) . PHP_EOL . PHP_EOL;
file_put_contents(FS_DIR_STORAGE . 'logs/debug.log', $log_message, FILE_APPEND);
return;
} else { }
}
}
}
}
}
$options = [];
$options[] = [
'id' => 'square',
'icon' => 'images/payment/square.jpg',
'name' => 'Square',
'description' => language::translate(__CLASS__.':description', 'Payments processing with Square'),
'fields' => '',
'cost' => 0,
'tax_class_id' => 0,
'confirm' => language::translate(__CLASS__.':title_pay_now', 'Pay Now'),
];
return [
'title' => $this->name,
'options' => $options,
];
}
public function transfer($order) {
try {
$order->save(); // Create order ID
$request = [
'idempotency_key' => uniqid(),
'checkout_options' => [
'redirect_url' => document::ilink('order_process')
],
'pre_populated_data' => [
'buyer_email' => $order->data['customer']['email'],
],
'cancel_url' => document::ilink('checkout'),
'order' => [
'location_id' => $this->settings['location_id'],
'reference_id' => strval($order->data['id']),
'name' => settings::get('store_name'),
'line_items' => [],
],
];
foreach ($order->data['items'] as $item) {
if ($item['price'] <= 0) continue;
$request['order']['line_items'][] = [
'name' => $item['name'],
'quantity' => strval((float)$item['quantity']),
'base_price_money' => [
'amount' => $this->_amount($item['price'] + $item['tax'], $order->data['currency_code'], $order->data['currency_value']),
'currency' => $order->data['currency_code'],
],
];
}
$result = $this->_call('POST', '/online-checkout/payment-links', $request);
session::$data['square']['order_id'] = $result['payment_link']['order_id'];
return [
'method' => 'GET',
'action' => $result['payment_link']['url'],
];
} catch (Exception $e) {
return ['error' => $e->getMessage()];
}
}
public function verify($order) {
try {
if (empty(session::$data['square']['order_id'])) {
throw new Exception('Missing order id');
}
$result = $this->_call('GET', '/orders/'. session::$data['square']['order_id']);
if (empty($result)) {
throw new Exception('Failed to create payment link');
}
return [
'is_payed' => 'true',
'payment_terms' => 'PWO',
'order_status_id' => $this->settings['order_status_id'],
'transaction_id' => $result['order']['id'],
];
} catch (Exception $e) {
return ['error' => $e->getMessage()];
}
}
private function _amount($amount, $currency_code, $currency_value) {
// Zero-decimal currencies
if (in_array($currency_code, explode(',', 'BIF,CLP,DJF,GNF,JPY,KMF,KRW,MGA,PYG,RWF,UGX,VND,VUV,XAF,XOF,XPF'))) {
return currency::format_raw($amount, $currency_code, $currency_value);
}
return currency::format_raw($amount, $currency_code, $currency_value) * 100;
}
private function _call($method, $endpoint, $request = null) {
$production_url = 'https://connect.squareup.com/v2';
$sandbox_url = 'https://connect.squareupsandbox.com/v2';
$base_url = '';
if (empty($this->settings['is_production'])) {
$base_url = $sandbox_url;
} else {
$base_url = $production_url;
}
$client = new wrap_http();
$headers = [
'Square-Version' => '2023-07-20',
'Authorization' => 'Bearer '. $this->settings['access_token'],
'Content-Type' => 'application/json',
];
$url = $base_url.$endpoint;
$log_message = '['. date('Y-m-d H:i:s e').'] calling square url: ' . $url . PHP_EOL . PHP_EOL;
file_put_contents(FS_DIR_STORAGE . 'logs/debug.log', $log_message, FILE_APPEND);
$log_message = 'with data: ' . json_encode($request) . PHP_EOL . PHP_EOL;
file_put_contents(FS_DIR_STORAGE . 'logs/debug.log', $log_message, FILE_APPEND);
$response = $client->call($method, $url, $request ? json_encode($request, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) : '', $headers);
if (!$result = json_decode($response, true)) {
throw new Exception('Invalid response from remote machine');
}
if (!empty($result['error'])) {
throw new Exception($result['error']['message']);
}
return $result;
}
function settings() {
return [
[
'key' => 'status',
'default_value' => '1',
'title' => language::translate(__CLASS__.':title_status', 'Status'),
'description' => language::translate(__CLASS__.':description_status', 'Enables or disables the module.'),
'function' => 'toggle("e/d")',
],
[
'key' => 'is_production',
'default_value' => '0',
'title' => language::translate(__CLASS__.':title_is_production', 'Is Production Mode'),
'description' => language::translate(__CLASS__.':description_status', 'Enables production mode or uses the sanbox for the module.'),
'function' => 'toggle("y/n")',
],
[
'key' => 'icon',
'default_value' => 'images/payment/square.jpg',
'title' => language::translate(__CLASS__.':title_icon', 'Icon'),
'description' => language::translate(__CLASS__.':description_icon', 'Path to an image to be displayed.'),
'function' => 'text()',
],
[
'key' => 'application_id',
'default_value' => '',
'title' => language::translate(__CLASS__.':title_application_id', 'Application ID'),
'description' => language::translate(__CLASS__.':description_application_id', 'Your application ID obtained from Square.'),
'function' => 'text()',
],
[
'key' => 'access_token',
'default_value' => '',
'title' => language::translate(__CLASS__.':title_access_token', 'Access Token'),
'description' => language::translate(__CLASS__.':description_access_token', 'Your access token obtained from Square.'),
'function' => 'text()',
],
[
'key' => 'location_id',
'default_value' => '',
'title' => language::translate(__CLASS__.':title_location_id', 'Location ID'),
'description' => language::translate(__CLASS__.':description_location_id', 'Your location id obtained from Square.'),
'function' => 'text()',
],
[
'key' => 'order_status_id',
'default_value' => '0',
'title' => language::translate(__CLASS__.':title_order_status', 'Order Status'),
'description' => language::translate(__CLASS__.':description_order_status', 'Give orders made with this payment module the following order status.'),
'function' => 'order_status()',
],
[
'key' => 'geo_zone_id',
'default_value' => '',
'title' => language::translate(__CLASS__.':title_geo_zone_limitation', 'Geo Zone Limitation'),
'description' => language::translate(__CLASS__.':description_geo_zone', 'Limit this module to the selected geo zone. Otherwise, leave it blank.'),
'function' => 'geo_zone()',
],
[
'key' => 'priority',
'default_value' => '0',
'title' => language::translate(__CLASS__.':title_priority', 'Priority'),
'description' => language::translate(__CLASS__.':description_priority', 'Process this module in the given priority order.'),
'function' => 'int()',
],
[
'key' => 'forbidden_items',
'default_value' => '',
'title' => language::translate(__CLASS__.':title_forbidden_Items', 'Forbidden Items'),
'description' => language::translate(__CLASS__.':description_forbidden_items', 'A comma separated list of items (by product ID#) for which this module should be disabled.'),
'function' => 'products()',
'multiple' => 'true',
],
[
'key' => 'forbidden_options',
'default_value' => '',
'title' => language::translate(__CLASS__.':title_forbidden_options', 'Forbidden Options'),
'description' => language::translate(__CLASS__.':description_forbidden_options', 'A comma separated list of payment options for which this module should be disabled.'),
'function' => 'attribute_groups()',
'multiple' => 'true',
],
];
}
public function install() {}
public function uninstall() {}
}