PageRenderTime 68ms CodeModel.GetById 38ms RepoModel.GetById 0ms app.codeStats 0ms

/fannie/modules/plugins2.0/PaycardFix/PaycardFixVoid.php

https://github.com/CORE-POS/IS4C
PHP | 319 lines | 278 code | 22 blank | 19 comment | 22 complexity | 604eb7d3971098dda43f5b9d0bfb4aff MD5 | raw file
  1. <?php
  2. include(__DIR__ . '/../../../config.php');
  3. if (!class_exists('FannieAPI')) {
  4. include(__DIR__ . '/../../../classlib2.0/FannieAPI.php');
  5. }
  6. if (!class_exists('MSoapClient')) {
  7. include(__DIR__ . '/../RecurringEquity/MSoapClient.php');
  8. }
  9. class PaycardFixVoid extends FannieRESTfulPage
  10. {
  11. protected $header = 'Refund Payment Card Transaction';
  12. protected $title = 'Refund Payment Card Transaction';
  13. public $discoverable = true;
  14. protected $must_authenticate = true;
  15. protected $auth_classes = array('admin');
  16. public function preprocess()
  17. {
  18. $this->addRoute('get<resultID>');
  19. return parent::preprocess();
  20. }
  21. private function paycardTransP($table)
  22. {
  23. return $this->connection->prepare("
  24. SELECT *
  25. FROM {$table}
  26. WHERE dateID=?
  27. AND refNum=?
  28. AND xResultCode=1
  29. AND xResultMessage LIKE '%approve%'
  30. AND xResultMessage NOT LIKE '%decline%'
  31. AND transType='Sale'
  32. AND xToken <> ''
  33. AND xToken IS NOT NULL
  34. ");
  35. }
  36. private function refnum($emp, $reg, $trans, $id)
  37. {
  38. $ref = "";
  39. $ref .= date("md");
  40. $ref .= str_pad($emp, 4, "0", STR_PAD_LEFT);
  41. $ref .= str_pad($reg, 2, "0", STR_PAD_LEFT);
  42. $ref .= str_pad($trans, 3, "0", STR_PAD_LEFT);
  43. $ref .= str_pad($id, 3, "0", STR_PAD_LEFT);
  44. return $ref;
  45. }
  46. protected function get_resultID_view()
  47. {
  48. $table = $this->config->get('TRANS_DB') . $this->connection->sep() . 'PaycardTransactions';
  49. $prep = $this->connection->prepare("SELECT * FROM {$table} WHERE storeRowID=? and dateID=?");
  50. $row = $this->connection->getRow($prep, array($this->resultID, date('Ymd')));
  51. $ret = '<table class="table table-bordered table-striped">';
  52. foreach ($row as $key => $val) {
  53. if (!is_numeric($key)) {
  54. $ret .= "<tr><th>{$key}</th><td>{$val}</td></tr>";
  55. }
  56. }
  57. $ret .= '</table>';
  58. return $ret;
  59. }
  60. /**
  61. * Process the actual refund. Long so comments are
  62. * internal
  63. */
  64. protected function post_handler()
  65. {
  66. try {
  67. $pDate = $this->form->date;
  68. $invoice = $this->form->invoice;
  69. } catch (Exception $ex) {
  70. echo 'Bad submission';
  71. return false;
  72. }
  73. $table = $this->config->get('TRANS_DB') . $this->connection->sep() . 'PaycardTransactions';
  74. $findP = $this->paycardTransP($table);
  75. $ptrans = $this->connection->getRow($findP, array(date('Ymd', strtotime($pDate)), $invoice));
  76. if ($ptrans == false) {
  77. echo 'Bad submission' . $pDate;
  78. return false;
  79. }
  80. // figure out POS transaction numbering depending whether this
  81. // is a new POS transaction or not
  82. $EMP = $ptrans['empNo'];
  83. $REG = $ptrans['registerNo'];
  84. $TRANS = $ptrans['transNo'];
  85. $TRANS_ID = $ptrans['transID'];
  86. $newInvoice = $this->refnum($EMP, $REG, $TRANS, $TRANS_ID);
  87. // prepare PaycardTransactions INSERT
  88. $ptransP = $this->connection->prepare("INSERT INTO {$table} (dateID, empNo, registerNo, transNo, transID,
  89. previousPaycardTransactionID, processor, refNum, live, cardType, transType, amount, PAN, issuer,
  90. name, manual, requestDatetime, responseDatetime, seconds, commErr, httpCode, validResponse,
  91. xResultCode, xApprovalNumber, xResponseCode, xResultMessage, xTransactionID, xBalance, xToken,
  92. xProcessorRef, xAcquirerRef) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
  93. $pcRow = array(
  94. date('Ymd'),
  95. $EMP,
  96. $REG,
  97. $TRANS,
  98. $TRANS_ID,
  99. $ptrans['paycardTransactionID'],
  100. $ptrans['processor'],
  101. $newInvoice,
  102. 1,
  103. 'CREDIT',
  104. 'VOID',
  105. $ptrans['amount'],
  106. $ptrans['PAN'],
  107. $ptrans['issuer'],
  108. $ptrans['name'],
  109. $ptrans['manual'],
  110. date('Y-m-d H:i:s'),
  111. );
  112. $credentials = json_decode(file_get_contents(__DIR__ . '/../RecurringEquity/credentials.json'), true);
  113. $storeID = $ptrans['registerNo'] < 10 ? 1 : 2;
  114. $hostOrIP = '127.0.0.1';
  115. if (!is_array($credentials) || !isset($credentials[$storeID])) {
  116. echo 'Cannot find acct info';
  117. return false;
  118. }
  119. $terminalID = '';
  120. if ($ptrans['processor'] == 'RapidConnect') {
  121. $hostOrIP = $credentials['hosts']['RapidConnect' . $storeID][0];
  122. $storeID = "RapidConnect" . $storeID;
  123. $terminalID = '<TerminalID>' . $credentials[$storeID][1] . '</TerminalID>';
  124. }
  125. $reqXML = <<<XML
  126. <?xml version="1.0"?>
  127. <TStream>
  128. <Transaction>
  129. <HostOrIP>{$hostOrIP}</HostOrIP>
  130. <IpPort>9000</IpPort>
  131. <MerchantID>{$credentials[$storeID][0]}</MerchantID>
  132. {$terminalID}
  133. <OperatorID>{$EMP}</OperatorID>
  134. <TranType>Credit</TranType>
  135. <TranCode>VoidSaleByRecordNo</TranCode>
  136. <SecureDevice>{{SecureDevice}}</SecureDevice>
  137. <ComPort>{{ComPort}}</ComPort>
  138. <InvoiceNo>{$newInvoice}</InvoiceNo>
  139. <RefNo>{$ptrans['xTransactionID']}</RefNo>
  140. <Amount>
  141. <Purchase>{$ptrans['amount']}</Purchase>
  142. </Amount>
  143. <Account>
  144. <AcctNo>SecureDevice</AcctNo>
  145. </Account>
  146. <LaneID>{$REG}</LaneID>
  147. <SequenceNo>{{SequenceNo}}</SequenceNo>
  148. <RecordNo>{$ptrans['xToken']}</RecordNo>
  149. <AuthCode>{$ptrans['xApprovalNumber']}</AuthCode>
  150. <Frequency>OneTime</Frequency>
  151. XML;
  152. if ($ptrans['xProcessorRef']) {
  153. $reqXML .= '<ProcessData>' . $ptrans['xProcessorRef'] . '</ProcessData>' . "\n";
  154. }
  155. if ($ptrans['xAcquirerRef']) {
  156. $reqXML .= '<AcqRefData>' . $ptrans['xAcquirerRef'] . '</AcqRefData>' . "\n";
  157. }
  158. $reqXML .= <<<XML
  159. </Transaction>
  160. </TStream>
  161. XML;
  162. $fp = fopen(__DIR__ . '/log.xml', 'a');
  163. fwrite($fp, $reqXML . "\n");
  164. $startTime = microtime(true);
  165. $success = false;
  166. $curl = curl_init('http://' . $credentials['hosts'][$storeID][0] . ':8999');
  167. curl_setopt($curl, CURLOPT_POST, 1);
  168. curl_setopt($curl, CURLOPT_POSTFIELDS, $reqXML);
  169. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  170. curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
  171. $respXML = curl_exec($curl);
  172. fwrite($fp, $respXML . "\n");
  173. $resp = simplexml_load_string($respXML);
  174. if (strlen($respXML) > 0 && $resp !== false) {
  175. $elapsed = microtime(true) - $startTime;
  176. $pcRow[] = date('Y-m-d H:i:s');
  177. $pcRow[] = $elapsed;
  178. $pcRow[] = 0;
  179. $pcRow[] = 200;
  180. $pcRow[] = 1; // valid response
  181. $status = strtolower($resp->CmdResponse->CmdStatus[0]);
  182. if ($status == 'approved') { // finish record as approved
  183. $success = true;
  184. $pcRow[] = 1;
  185. $pcRow[] = $resp->TranResponse->AuthCode[0];
  186. $pcRow[] = $resp->CmdResponse->DSIXReturnCode[0];
  187. $pcRow[] = $resp->CmdResponse->TextResponse[0];
  188. $pcRow[] = $resp->TranResponse->RefNo[0];
  189. $pcRow[] = 0; // xBalance
  190. $pcRow[] = $resp->TranResponse->RecordNo[0];
  191. $pcRow[] = $resp->TranResponse->ProcessData[0];
  192. $pcRow[] = $resp->TranResponse->AcqRefData[0];
  193. } else { // finish record as declined or errored
  194. $pcRow[] = $status == 'declined' ? 2 : 3;
  195. $pcRow[] = ''; // xApprovalNumber
  196. $pcRow[] = $resp->CmdResponse->DSIXReturnCode[0];
  197. $pcRow[] = $status == 'declined' ? 'DECLINED' : $resp->CmdResponse->TextResponse[0];
  198. $pcRow[] = ''; // xTransactionID
  199. $pcRow[] = 0; // xBalance
  200. $pcRow[] = ''; // xToken
  201. $pcRow[] = ''; // xProcessorRef
  202. $pcRow[] = ''; // xAcquirerRef
  203. }
  204. } else {
  205. $elapsed = microtime(true) - $startTime;
  206. $pcRow[] = date('Y-m-d H:i:s');
  207. $pcRow[] = $elapsed;
  208. $pcRow[] = curl_errno($curl);
  209. $pcRow[] = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
  210. $pcRow[] = 1; // valid response
  211. $pcRow[] = 3; // xResultCode
  212. $pcRow[] = ''; // xApprovalNumber
  213. $pcRow[] = 0; // xResponseCode
  214. $pcRow[] = curl_error($curl);
  215. $pcRow[] = ''; // xTransactionID
  216. $pcRow[] = 0; // xBalance
  217. $pcRow[] = ''; // xToken
  218. $pcRow[] = ''; // xProcessorRef
  219. $pcRow[] = ''; // xAcquirerRef
  220. }
  221. $this->connection->execute($ptransP, $pcRow);
  222. $pcID = $this->connection->insertID();
  223. return 'PaycardFixVoid.php?resultID=' . $pcID;
  224. }
  225. /**
  226. * Validate the submitted form info
  227. *
  228. * Make sure that:
  229. * 1. PaycardTransaction record exists
  230. * 2. PaycardTransaction record is unique
  231. *
  232. * If validation succeeds, create a POST form to continue
  233. */
  234. protected function get_id_view()
  235. {
  236. try {
  237. $pDate = trim($this->form->date);
  238. } catch (Exception $ex) {
  239. return '<div class="alert alert-danger">Invalid data</div>'
  240. . $this->get_view();
  241. }
  242. $table = $this->config->get('TRANS_DB') . $this->connection->sep() . 'PaycardTransactions';
  243. $findP = $this->paycardTransP($table);
  244. $findR = $this->connection->execute($findP, array(date('Ymd', strtotime($pDate)), $this->id));
  245. if ($this->connection->numRows($findR) == 0) {
  246. return '<div class="alert alert-danger">Paycard transaction not found</div>'
  247. . $this->get_view();
  248. }
  249. if ($this->connection->numRows($findR) > 1) {
  250. return '<div class="alert alert-danger">Multiple matching transactions; cannot continue</div>'
  251. . $this->get_view();
  252. }
  253. $ptrans = $this->connection->fetchRow($findR);
  254. return <<<HTML
  255. <p>
  256. Voidng \${$ptrans['amount']} payment on card {$ptrans['PAN']}.
  257. </p>
  258. <form method="post" action="PaycardFixVoid.php">
  259. <input type="hidden" name="date" value="{$pDate}" />
  260. <input type="hidden" name="invoice" value="{$this->id}" />
  261. <div class="form-group">
  262. <button type="submit" class="btn btn-default btn-core">Process Void</button>
  263. </div>
  264. </form>
  265. HTML;
  266. }
  267. /**
  268. * Create a form to start the refund process
  269. */
  270. protected function get_view()
  271. {
  272. return <<<HTML
  273. <p class="well">
  274. This will try to run a void transaction via Mercury.
  275. If you've already issued a refund to the card (e.g., by calling the processor)
  276. use <a href="PaycardFixGeneric.php">this tool</a> instead to create a corresponding
  277. POS transaction.
  278. </p>
  279. <form method="get">
  280. <div class="form-group">
  281. <label>Card Transaction Date</label>
  282. <input type="text" class="form-control date-field" required name="date" />
  283. </div>
  284. <div class="form-group">
  285. <label>Card Transaction Invoice #</label>
  286. <input type="text" class="form-control" required name="id" />
  287. </div>
  288. <div class="form-group">
  289. <button type="submit" class="btn btn-default btn-core">Continue</button>
  290. </div>
  291. </form>
  292. HTML;
  293. }
  294. }
  295. FannieDispatch::conditionalExec();