public function checkout($params = []){
try{
if( empty($params['section']) || empty($params['representative']) ){
throw new \Exception('INVALID_DATA');
}
if(!empty($params['onsite_secret'])){
$this->onsite = $this->is_onsite([
'secret' => $params['onsite_secret']
]);
}
if(!empty($params['pay_by_cash']) && $params['pay_by_cash'] == true && !$this->onsite){
throw new \Exception('INVALID_PAYMENT_METHOD');
}
global $DB;
$res = $DB->prepare("SELECT * FROM `event` WHERE `url_alias` = ? AND `deleted` = 0 LIMIT 1");
$res->execute([
$params['section']
]);
$event = $res->fetch(\PDO::FETCH_ASSOC);
if( empty($event) ){
throw new \Exception('INVALID_EVENT');
}
$res = $DB->prepare("SELECT * FROM `event_visitor_type` WHERE `event_id` = ? AND `id` = ? LIMIT 1");
$res->execute([
$event['id'],
$params['visitor_type']
]);
$visitor_type = $res->fetch(\PDO::FETCH_ASSOC);
if( empty($visitor_type) ){
throw new \Exception('INVALID_VISITOR_TYPE');
}
$coupon_type = NULL;
$modifier = -1;
if($params['coupon_applied'] == true && !empty($params['coupon_code'])){
$res = $DB->prepare("SELECT * FROM `coupon` WHERE `event_id` = ? AND `coupon_code` = ?");
$res->execute([
$event['id'],
$params['coupon_code']
]);
$coupon = $res->fetch(\PDO::FETCH_ASSOC);
if (empty($coupon)) {
throw new \Exception('INVALID_COUPON_CODE');
}
if ($coupon['coupon_start_time'] > time()) {
throw new \Exception('COUPON_NOT_AVAILABLE_YET');
}
if (time() > $coupon['coupon_end_time']) {
throw new \Exception('COUPON_EXPIRED');
}
if($coupon['redemption_quota'] > 0 && $coupon['redeemed'] >= $coupon['redemption_quota']){
throw new \Exception('REDEMPTION_QUOTA_REACHED');
}
$coupon_type = $coupon['type'];
$modifier = floatval($coupon['modifier']);
}
$original_price = ((!empty($params['accompany']) ? count($params['accompany']) : 0) + 1) * floatval($visitor_type['price']);
$total = floatval($params['total']);
$discounted_price = empty($coupon_type) || $modifier > -1 ? $original_price : ($coupon_type === 'Percentage' ? $original_price * $modifier : ($coupon_type === 'Lump-sum' ? $original_price + $modifier : $original_price));
if($total !== $discounted_price){
throw new \Exception('INVALID_TOTAL_PRICE');
}
$payment_method = $total > 0 ? ($params['pay_by_cash'] == true ? 'cash' : 'paypal') : '';
$secret = md5(uniqid());
$language_id_map = [
'en_gb' => 1,
'zh_hk' => 2,
'zh_cn' => 3
];
$res = $DB->prepare("INSERT INTO `registration` (`event_id`, `event_visitor_type_id`, `accompany_count`, `language_id`, `price`, `coupon_code`, `coupon_modifier`, `final_price`, `payment_method`, `approval_status`, `secret`, `create_time`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$res->execute([
$event['id'],
$params['visitor_type'],
!empty($params['accompany']) ? count($params['accompany']) : 0,
$language_id_map[ $params['language'] ],
floatval($original_price),
!empty($coupon['coupon_code']) ? $coupon['coupon_code'] : '',
$modifier,
$total,
$payment_method,
!$this->onsite && $event['approval_required'] == 1 ? -1 : 1,
$secret,
time()
]);
$registration_id = $DB->lastInsertId();
if(empty($registration_id)){
throw new \Exception('Failed to register! Please try again later, or contact us!');
}
$invoice_id = (!empty($event['invoice_prefix']) ? str_replace('', '', $event['invoice_prefix']) : 'GENERAL'). '_'. $registration_id;
if(!empty($coupon_type) && !empty($modifier)){
$res = $DB->prepare("UPDATE `coupon` SET `redeemed` = `redeemed` + 1 WHERE `id` = ? LIMIT 1");
$res->execute([
$coupon['id']
]);
}
$duplicated_value_for_search_key = ['`invoice_id` = ?'];
$duplicated_value_for_search_value = [$invoice_id];
foreach($params['representative'] AS $question_id => $answer){
$answer_value = is_array($answer) ? ($this->is_multidimensional_array($answer) ? $this->multi_implode("\n", $answer) : (is_numeric(implode('', $answer)) ? implode(' ', $answer) : implode("\n", $answer))) : $answer;
$res = $DB->prepare("INSERT INTO `registration_representative` (`registration_id`, `question_id`, `answer`) VALUES (?, ?, ?)");
$res->execute([
$registration_id,
$question_id,
$answer_value
]);
if($question_id < 0){
switch($question_id){
case -8:
$duplicated_value_for_search_key[] = '`country` = ?';
break;
case -7:
$duplicated_value_for_search_key[] = '`job_title` = ?';
break;
case -6:
$duplicated_value_for_search_key[] = '`salutation` = ?';
break;
case -5:
$duplicated_value_for_search_key[] = '`first_name` = ?';
break;
case -4:
$duplicated_value_for_search_key[] = '`last_name` = ?';
break;
case -3:
$duplicated_value_for_search_key[] = '`company` = ?';
break;
case -2:
$duplicated_value_for_search_key[] = '`email_address` = ?';
break;
case -1:
$duplicated_value_for_search_key[] = '`mobile_phone_number` = ?';
break;
default:
}
$duplicated_value_for_search_value[] = $answer_value;
}
}
if(!empty($duplicated_value_for_search_key) && !empty($duplicated_value_for_search_value)){
$res = $DB->prepare("UPDATE `registration` SET ". implode(', ', $duplicated_value_for_search_key). " WHERE `id` = ? LIMIT 1");
$res->execute(array_merge(
$duplicated_value_for_search_value,
[$registration_id]
));
}
if( !empty($params['accompany']) ){
foreach($params['accompany'] AS $accompany_id => $accompany){
foreach($accompany AS $question_id => $answer){
$res = $DB->prepare("INSERT INTO `registration_accompany` (`registration_id`, `accompany_id`, `question_id`, `answer`) VALUES (?, ?, ?, ?)");
$res->execute([
$registration_id,
$accompany_id + 1,
$question_id,
is_array($answer) ? implode(' ', $answer) : $answer
]);
}
}
}
if(!$this->onsite && $event['approval_required'] == 1){
$payment_method = 'pending';
}elseif($payment_method === 'paypal'){
$paypal_params = [
'METHOD' => 'SetExpressCheckout',
'VERSION' => '124.0',
'USER' => PAYPAL_USER,
'PWD' => PAYPAL_PWD,
'SIGNATURE' => PAYPAL_SIGNATURE,
'LOCALECODE' => 'en_GB',
'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
'PAYMENTREQUEST_0_CURRENCYCODE' => 'USD',
'L_PAYMENTREQUEST_0_NAME0' => $event['name_'. $params['language']]. ' - '. $visitor_type['name_'. $params['language']],
'L_PAYMENTREQUEST_0_QTY0' => 1 + (!empty($params['accompany']) ? count($params['accompany']) : 0),
'L_PAYMENTREQUEST_0_AMT0' => floatval($visitor_type['price']),
'PAYMENTREQUEST_0_AMT' => $total,
'PAYMENTREQUEST_0_ITEMAMT' => $total,
'PAYMENTREQUEST_0_INVNUM' => $invoice_id,
'RETURNURL' => WWW_URL_ROOT. '#/'. $params['language']. '/'. $params['section']. '/payment/'. ($this->onsite ? '?onsite_secret='. $params['onsite_secret'] : ''),
'CANCELURL' => WWW_URL_ROOT. '#/'. $params['language']. '/'. $params['section']. '/canceled/'. ($this->onsite ? '?onsite_secret='. $params['onsite_secret'] : '')
];
if(!empty($coupon_type)){
$paypal_params['L_PAYMENTREQUEST_0_NAME1'] = 'Coupon Code ('. $coupon['coupon_code']. ')';
$paypal_params['L_PAYMENTREQUEST_0_QTY1'] = 1;
$paypal_params['L_PAYMENTREQUEST_0_AMT1'] = $discounted_price - $original_price;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, PAYPAL_API);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($paypal_params));
$res = curl_exec($ch);
curl_close($ch);
$paypal_returned_values = array();
parse_str($res, $paypal_returned_values);
if(empty($res) || empty($paypal_returned_values) || empty($paypal_returned_values['ACK'])){
throw new \Exception ('Express-checkout failed');
}elseif($paypal_returned_values['ACK'] !== 'Success'){
throw new \Exception ($paypal_returned_values['L_SEVERITYCODE0']. ': '. $paypal_returned_values['L_LONGMESSAGE0']. ' ('. $paypal_returned_values['L_ERRORCODE0']. ')');
}
}elseif($total == 0){
$this->send_confirmation_email(array_merge(['registration_id' => $registration_id], $params));
}
$success = true;
} catch (\Exception $ex) {
$success = false;
$msg = $ex->getMessage();
}
return array(
'success' => $success,
'msg' => !empty($msg) ? $msg : NULL,
'data' => [
'registration_id' => $registration_id,
'payment_method' => $payment_method,
'url' => !empty($paypal_returned_values['TOKEN']) ? (PAYPAL_CHECKOUT_URL. '?cmd=_express-checkout&token='. $paypal_returned_values['TOKEN']. '&useraction=commit') : NULL,
'barcode' => $this->onsite ? json_encode([
'id' => $registration_id,
'secret' => $secret
]) : NULL
]
);
}
Comments