1
0

BxXeroModule.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup Xero Xero
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. define('BX_XERO_ACCOUNT_CODE_SALES', 200);
  12. define('BX_XERO_ACCOUNT_CODE_PURCHASES', 300);
  13. define('BX_XERO_ACCOUNT_CODE_ADVERTIXING', 400);
  14. class BxXeroModule extends BxDolModule
  15. {
  16. protected $_oApi;
  17. protected $_oLog;
  18. function __construct($aModule)
  19. {
  20. parent::__construct($aModule);
  21. $this->_oConfig->init($this->_oDb);
  22. bx_import('Api', $aModule);
  23. $this->_oApi = new BxXeroApi($this);
  24. }
  25. /**
  26. * ACTION METHODS
  27. */
  28. public function actionAuthorize()
  29. {
  30. header('Location: ' . $this->_oApi->authorize());
  31. exit;
  32. }
  33. public function actionCallback()
  34. {
  35. $sCode = bx_process_input(bx_get('code'));
  36. if($sCode === false) {
  37. header('Location: ' . $this->_oConfig->getAuthorizeUrl(1));
  38. exit();
  39. }
  40. if(($sState = bx_get('state')) === false || $sState != $this->_oConfig->getState()) {
  41. $this->_oConfig->unsetState();
  42. header('Location: ' . $this->_oConfig->getAuthorizeUrl(2));
  43. exit();
  44. }
  45. $sUrl = $this->_oApi->callback($sCode);
  46. if($sUrl === false)
  47. $sUrl = $this->_oConfig->getAuthorizeUrl(3);
  48. header('Location: ' . $sUrl);
  49. exit();
  50. }
  51. public function actionWebhook()
  52. {
  53. $sResponse = file_get_contents('php://input');
  54. $sSignatureComputed = base64_encode(hash_hmac('sha256', $sResponse, $this->_oConfig->getWebhookKey(), true));
  55. $sSignatureReceived = isset($_SERVER['HTTP_X_XERO_SIGNATURE']) ? $_SERVER['HTTP_X_XERO_SIGNATURE'] : '';
  56. if(!hash_equals($sSignatureComputed, $sSignatureReceived)) {
  57. bx_log($this->getName(), ":\n[Core] Get Webhook: Wrong Signature (" . $sSignatureComputed . ", " . $sSignatureReceived . ")", BX_LOG_ERR);
  58. http_response_code(401);
  59. return;
  60. }
  61. http_response_code(200);
  62. $aResponce = json_decode($sResponse, true);
  63. if(empty($aResponce) || !is_array($aResponce))
  64. return;
  65. foreach($aResponce['events'] as $aEvent) {
  66. $sMethod = '_process' . bx_gen_method_name(strtolower($aEvent['eventType']) . '_' . strtolower($aEvent['eventCategory']));
  67. if(!method_exists($this, $sMethod))
  68. continue;
  69. $this->$sMethod($aEvent['resourceId']);
  70. }
  71. }
  72. public function actionTest()
  73. {
  74. $mixedResult = $this->_oApi->actionTest();
  75. if($mixedResult !== false)
  76. $mixedResult = _t('_bx_xero_txt_organization', $mixedResult);
  77. else
  78. $mixedResult = _t('_bx_xero_txt_err_unknown');
  79. echo $mixedResult;
  80. }
  81. /**
  82. * SERVICE METHODS
  83. */
  84. public function serviceIncludeCssJs()
  85. {
  86. return $this->_oTemplate->getIncludeCssJs();
  87. }
  88. public function serviceIsContact($iProfileId, $bForceCheckApi = false)
  89. {
  90. $oProfile = BxDolProfile::getInstance($iProfileId);
  91. if(!$oProfile)
  92. return false;
  93. $sProfileEmail = $oProfile->getAccountObject()->getEmail();
  94. return $this->isContact($sProfileEmail, $bForceCheckApi);
  95. }
  96. public function serviceAddContact($iProfileId)
  97. {
  98. $oProfile = BxDolProfile::getInstance($iProfileId);
  99. if(!$oProfile)
  100. return false;
  101. $sProfileName = $oProfile->getDisplayName();
  102. $sProfileEmail = $oProfile->getAccountObject()->getEmail();
  103. return $this->_oApi->actionAddContact($iProfileId, $sProfileName, $sProfileEmail);
  104. }
  105. public function serviceAddInvoce($iProfileId, $sName, $mixedAmount, $iQuantity = 1, $mixedDueDate = false)
  106. {
  107. $oProfile = BxDolProfile::getInstance($iProfileId);
  108. if(!$oProfile)
  109. return false;
  110. $sProfileEmail = $oProfile->getAccountObject()->getEmail();
  111. return $this->addInvoice($sProfileEmail, $sName, $mixedAmount, $iQuantity, $mixedDueDate);
  112. }
  113. public function serviceAddInvoceAuto($iProfileId, $sName, $mixedAmount, $iQuantity = 1, $mixedDueDate = false)
  114. {
  115. $oProfile = BxDolProfile::getInstance($iProfileId);
  116. if(!$oProfile)
  117. return false;
  118. $sProfileEmail = $oProfile->getAccountObject()->getEmail();
  119. if(!$this->isContact($sProfileEmail)) {
  120. $sProfileName = $oProfile->getDisplayName();
  121. if($this->_oApi->actionAddContact($iProfileId, $sProfileName, $sProfileEmail) === false)
  122. return false;
  123. }
  124. return $this->addInvoice($sProfileEmail, $sName, $mixedAmount, $iQuantity, $mixedDueDate);
  125. }
  126. /*
  127. * COMMON METHODS
  128. */
  129. public function getApi()
  130. {
  131. return $this->_oApi;
  132. }
  133. public function isContact($sProfileEmail, $bForceCheckApi = false)
  134. {
  135. if(!$bForceCheckApi && $this->_oDb->isContact($sProfileEmail))
  136. return true;
  137. return $this->_oApi->actionIsContact($sProfileEmail);
  138. }
  139. public function addInvoice($sProfileEmail, $sName, $mixedAmount, $iQuantity, $mixedDueDate)
  140. {
  141. $CNF = &$this->_oConfig->CNF;
  142. $mixedInvoiceId = $this->_oApi->actionAddInvoice($sProfileEmail, $sName, $mixedAmount, $iQuantity, $mixedDueDate);
  143. if(!$mixedInvoiceId)
  144. return $mixedInvoiceId;
  145. if(getParam($CNF['PARAM_INVOICE_SEND']) == 'on')
  146. $this->_oApi->sendInvoice($mixedInvoiceId);
  147. return $mixedInvoiceId;
  148. }
  149. /*
  150. * INTERNAL METHODS
  151. */
  152. protected function _processCreateInvoice($sId)
  153. {
  154. $oInvoice = $this->_oApi->actionGetInvoice($sId);
  155. $aInvoice = $this->_getInvoiceData($oInvoice);
  156. bx_log($this->getName(), [
  157. ":\n[Core] Create Invoice: " . $sId,
  158. $aInvoice
  159. ], BX_LOG_ERR);
  160. bx_alert($this->_oConfig->getName(), 'invoice_created', 0, 0, array(
  161. 'id' => $sId,
  162. 'invoice' => $aInvoice,
  163. ));
  164. }
  165. protected function _processUpdateInvoice($sId)
  166. {
  167. $oInvoice = $this->_oApi->actionGetInvoice($sId);
  168. $aInvoice = $this->_getInvoiceData($oInvoice);
  169. bx_log($this->getName(), [
  170. ":\n[Core] Update Invoice: " . $sId,
  171. $aInvoice
  172. ], BX_LOG_ERR);
  173. bx_alert($this->_oConfig->getName(), 'invoice_updated', 0, 0, array(
  174. 'id' => $sId,
  175. 'invoice' => $aInvoice,
  176. ));
  177. }
  178. protected function _getInvoiceData($oInvoice)
  179. {
  180. return [
  181. 'id' => $oInvoice->getInvoiceId(),
  182. 'number' => $oInvoice->getInvoiceNumber(),
  183. 'reference' => $oInvoice->getReference(),
  184. 'currency_code' => $oInvoice->getCurrencyCode(),
  185. 'sub_total' => $oInvoice->getSubTotal(),
  186. 'total_tax' => $oInvoice->getTotalTax(),
  187. 'total' => $oInvoice->getTotal(),
  188. 'amount_due' => $oInvoice->getAmountDue(),
  189. 'amount_paid' => $oInvoice->getAmountPaid(),
  190. 'status' => $oInvoice->getStatus(),
  191. ];
  192. }
  193. }
  194. /** @} */