PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/app/code/core/Mage/Paypal/Model/Report/Settlement.php

https://bitbucket.org/andrewjleavitt/magestudy
PHP | 381 lines | 238 code | 22 blank | 121 comment | 22 complexity | e04dd113153059db5e9e0328f7faec36 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Paypal
  23. * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /*
  27. * Paypal Settlement Report model
  28. *
  29. * Perform fetching reports from remote servers with following saving them to database
  30. * Prepare report rows for Mage_Paypal_Model_Report_Settlement_Row model
  31. *
  32. */
  33. class Mage_Paypal_Model_Report_Settlement extends Mage_Core_Model_Abstract
  34. {
  35. /**
  36. * Default PayPal SFTP host
  37. * @var string
  38. */
  39. const REPORTS_HOSTNAME = "reports.paypal.com";
  40. /**
  41. * Default PayPal SFTP host for sandbox mode
  42. * @var string
  43. */
  44. const SANDBOX_REPORTS_HOSTNAME = "reports.sandbox.paypal.com";
  45. /**
  46. * PayPal SFTP path
  47. * @var string
  48. */
  49. const REPORTS_PATH = "/ppreports/outgoing";
  50. /**
  51. * Original charset of report files
  52. * @var string
  53. */
  54. const FILES_IN_CHARSET = "UTF-16";
  55. /**
  56. * Target charset of report files to be parsed
  57. * @var string
  58. */
  59. const FILES_OUT_CHARSET = "UTF-8";
  60. /**
  61. * Reports rows storage
  62. * @var array
  63. */
  64. protected $_rows = array();
  65. /**
  66. * Initialize resource model
  67. */
  68. protected function _construct()
  69. {
  70. $this->_init('paypal/report_settlement');
  71. }
  72. /**
  73. * Stop saving process if file with same report date, account ID and last modified date was already ferched
  74. *
  75. * @return Mage_Core_Model_Abstract
  76. */
  77. protected function _beforeSave()
  78. {
  79. $this->_dataSaveAllowed = true;
  80. if ($this->getId()) {
  81. if ($this->getLastModified() == $this->getReportLastModified()) {
  82. $this->_dataSaveAllowed = false;
  83. }
  84. }
  85. $this->setLastModified($this->getReportLastModified());
  86. return parent::_beforeSave();
  87. }
  88. /**
  89. * Goes to specified host/path and fetches reports from there.
  90. * Save reports to database.
  91. *
  92. * @param array $config SFTP credentials
  93. * @return int Number of report rows that were fetched and saved successfully
  94. */
  95. public function fetchAndSave($config)
  96. {
  97. $connection = new Varien_Io_Sftp();
  98. $connection->open(array(
  99. 'host' => $config['hostname'],
  100. 'username' => $config['username'],
  101. 'password' => $config['password']
  102. ));
  103. $connection->cd($config['path']);
  104. $fetched = 0;
  105. $listing = $this->_filterReportsList($connection->rawls());
  106. foreach ($listing as $filename => $attributes) {
  107. $localCsv = tempnam(Mage::getConfig()->getOptions()->getTmpDir(), 'PayPal_STL');
  108. if ($connection->read($filename, $localCsv)) {
  109. if (!is_writable($localCsv)) {
  110. Mage::throwException(Mage::helper('paypal')->__('Cannot create target file for reading reports.'));
  111. }
  112. $encoded = file_get_contents($localCsv);
  113. $decoded = @iconv(self::FILES_IN_CHARSET, self::FILES_OUT_CHARSET.'//IGNORE', $encoded);
  114. file_put_contents($localCsv, $decoded);
  115. // Set last modified date, this value will be overwritten during parsing
  116. if (isset($attributes['mtime'])) {
  117. $lastModified = new Zend_Date($attributes['mtime']);
  118. $this->setReportLastModified($lastModified->toString(Varien_Date::DATETIME_INTERNAL_FORMAT));
  119. }
  120. $this->setReportDate($this->_fileNameToDate($filename))
  121. ->setFilename($filename)
  122. ->parseCsv($localCsv);
  123. if ($this->getAccountId()) {
  124. $this->save();
  125. }
  126. if ($this->_dataSaveAllowed) {
  127. $fetched += count($this->_rows);
  128. }
  129. // clean object and remove parsed file
  130. $this->unsetData();
  131. unlink($localCsv);
  132. }
  133. }
  134. return $fetched;
  135. }
  136. /**
  137. * Parse CSV file and collect report rows
  138. *
  139. * @param string $localCsv Path to CSV file
  140. * @return Mage_Paypal_Model_Report_Settlement
  141. */
  142. public function parseCsv($localCsv)
  143. {
  144. $this->_rows = array();
  145. $section_columns = array('' => 0,
  146. 'TransactionID' => 1,
  147. 'InvoiceID' => 2,
  148. 'PayPalReferenceID' => 3,
  149. 'PayPalReferenceIDType' => 4,
  150. 'TransactionEventCode' => 5,
  151. 'TransactionInitiationDate' => 6,
  152. 'TransactionCompletionDate' => 7,
  153. 'TransactionDebitOrCredit' => 8,
  154. 'GrossTransactionAmount' => 9,
  155. 'GrossTransactionCurrency' => 10,
  156. 'FeeDebitOrCredit' => 11,
  157. 'FeeAmount' => 12,
  158. 'FeeCurrency' => 13,
  159. 'CustomField' => 14,
  160. 'ConsumerID' => 15,
  161. );
  162. $rowmap = array(
  163. 'TransactionID' => 'transaction_id',
  164. 'InvoiceID' => 'invoice_id',
  165. 'PayPalReferenceID' => 'paypal_reference_id',
  166. 'PayPalReferenceIDType' => 'paypal_reference_id_type',
  167. 'TransactionEventCode' => 'transaction_event_code',
  168. 'TransactionInitiationDate' => 'transaction_initiation_date',
  169. 'TransactionCompletionDate' => 'transaction_completion_date',
  170. 'TransactionDebitOrCredit' => 'transaction_debit_or_credit',
  171. 'GrossTransactionAmount' => 'gross_transaction_amount',
  172. 'GrossTransactionCurrency' => 'gross_transaction_currency',
  173. 'FeeDebitOrCredit' => 'fee_debit_or_credit',
  174. 'FeeAmount' => 'fee_amount',
  175. 'FeeCurrency' => 'fee_currency',
  176. 'CustomField' => 'custom_field',
  177. 'ConsumerID' => 'consumer_id',
  178. );
  179. $flipped_section_columns = array_flip($section_columns);
  180. $fp = fopen($localCsv, 'r');
  181. while($line = fgetcsv($fp)) {
  182. if (empty($line)) { // The line was empty, so skip it.
  183. continue;
  184. }
  185. $lineType = $line[0];
  186. switch($lineType) {
  187. case 'RH': // Report header.
  188. $lastModified = new Zend_Date($line[1]);
  189. $this->setReportLastModified($lastModified->toString(Varien_Date::DATETIME_INTERNAL_FORMAT));
  190. //$this->setAccountId($columns[2]); -- probably we'll just take that from the section header...
  191. break;
  192. case 'FH': // File header.
  193. // Nothing interesting here, move along
  194. break;
  195. case 'SH': // Section header.
  196. $this->setAccountId($line[3]);
  197. $this->loadByAccountAndDate();
  198. break;
  199. case 'CH': // Section columns.
  200. // In case ever the column order is changed, we will have the items recorded properly
  201. // anyway. We have named, not numbered columns.
  202. for ($i = 1; $i < count($line); $i++) {
  203. $section_columns[$line[$i]] = $i;
  204. }
  205. $flipped_section_columns = array_flip($section_columns);
  206. break;
  207. case 'SB': // Section body.
  208. $bodyitem = array();
  209. for($i = 1; $i < count($line); $i++) {
  210. $bodyitem[$rowmap[$flipped_section_columns[$i]]] = $line[$i];
  211. }
  212. $this->_rows[] = $bodyitem;
  213. break;
  214. case 'SC': // Section records count.
  215. case 'RC': // Report records count.
  216. case 'SF': // Section footer.
  217. case 'FF': // File footer.
  218. case 'RF': // Report footer.
  219. // Nothing to see here, move along
  220. break;
  221. }
  222. }
  223. return $this;
  224. }
  225. /**
  226. * Load report by unique key (accoutn + report date)
  227. *
  228. * @return Mage_Paypal_Model_Report_Settlement
  229. */
  230. public function loadByAccountAndDate()
  231. {
  232. $this->getResource()->loadByAccountAndDate($this, $this->getAccountId(), $this->getReportDate());
  233. return $this;
  234. }
  235. /**
  236. * Return collected rows for further processing.
  237. *
  238. * @return array
  239. */
  240. public function getRows()
  241. {
  242. return $this->_rows;
  243. }
  244. /**
  245. * Return name for row column
  246. *
  247. * @param string $field Field name in row model
  248. * @return string
  249. */
  250. public function getFieldLabel($field)
  251. {
  252. switch ($field) {
  253. case 'report_date':
  254. return Mage::helper('paypal')->__('Report Date');
  255. case 'account_id':
  256. return Mage::helper('paypal')->__('Merchant Account');
  257. case 'transaction_id':
  258. return Mage::helper('paypal')->__('Transaction ID');
  259. case 'invoice_id':
  260. return Mage::helper('paypal')->__('Invoice ID');
  261. case 'paypal_reference_id':
  262. return Mage::helper('paypal')->__('PayPal Reference ID');
  263. case 'paypal_reference_id_type':
  264. return Mage::helper('paypal')->__('PayPal Reference ID Type');
  265. case 'transaction_event_code':
  266. return Mage::helper('paypal')->__('Event Code');
  267. case 'transaction_event':
  268. return Mage::helper('paypal')->__('Event');
  269. case 'transaction_initiation_date':
  270. return Mage::helper('paypal')->__('Initiation Date');
  271. case 'transaction_completion_date':
  272. return Mage::helper('paypal')->__('Completion Date');
  273. case 'transaction_debit_or_credit':
  274. return Mage::helper('paypal')->__('Debit or Credit');
  275. case 'gross_transaction_amount':
  276. return Mage::helper('paypal')->__('Gross Amount');
  277. case 'fee_debit_or_credit':
  278. return Mage::helper('paypal')->__('Fee Debit or Credit');
  279. case 'fee_amount':
  280. return Mage::helper('paypal')->__('Fee Amount');
  281. case 'custom_field':
  282. return Mage::helper('paypal')->__('Custom');
  283. default:
  284. return $field;
  285. }
  286. }
  287. /**
  288. * Iterate through website configurations and collect all SFTP configurations
  289. * Filter config values if necessary
  290. *
  291. * @param bool $automaticMode Whether to skip settings with disabled Automatic Fetching or not
  292. * @return array
  293. */
  294. public function getSftpCredentials($automaticMode = false)
  295. {
  296. $configs = array();
  297. $uniques = array();
  298. foreach(Mage::app()->getStores() as $store) {
  299. /*@var $store Mage_Core_Model_Store */
  300. $active = (bool)$store->getConfig('paypal/fetch_reports/active');
  301. if (!$active && $automaticMode) {
  302. continue;
  303. }
  304. $cfg = array(
  305. 'hostname' => $store->getConfig('paypal/fetch_reports/ftp_ip'),
  306. 'path' => $store->getConfig('paypal/fetch_reports/ftp_path'),
  307. 'username' => $store->getConfig('paypal/fetch_reports/ftp_login'),
  308. 'password' => $store->getConfig('paypal/fetch_reports/ftp_password'),
  309. 'sandbox' => $store->getConfig('paypal/fetch_reports/ftp_sandbox'),
  310. );
  311. if (empty($cfg['username']) || empty($cfg['password'])) {
  312. continue;
  313. }
  314. if (empty($cfg['hostname']) || $cfg['sandbox']) {
  315. $cfg['hostname'] = $cfg['sandbox'] ? self::SANDBOX_REPORTS_HOSTNAME : self::REPORTS_HOSTNAME;
  316. }
  317. if (empty($cfg['path']) || $cfg['sandbox']) {
  318. $cfg['path'] = self::REPORTS_PATH;
  319. }
  320. // avoid duplicates
  321. if (in_array(serialize($cfg), $uniques)) {
  322. continue;
  323. }
  324. $uniques[] = serialize($cfg);
  325. $configs[] = $cfg;
  326. }
  327. return $configs;
  328. }
  329. /**
  330. * Converts a filename to date of report.
  331. *
  332. * @param string $filename
  333. * @return string
  334. */
  335. protected function _fileNameToDate($filename)
  336. {
  337. // Currently filenames look like STL-YYYYMMDD, so that is what we care about.
  338. $dateSnippet = substr(basename($filename), 4, 8);
  339. $result = substr($dateSnippet, 0, 4).'-'.substr($dateSnippet, 4, 2).'-'.substr($dateSnippet, 6, 2);
  340. return $result;
  341. }
  342. /**
  343. * Filter SFTP file list by filename format
  344. *
  345. * @param array $list List of files as per $connection->rawls()
  346. * @return array Trimmed down list of files
  347. */
  348. protected function _filterReportsList($list)
  349. {
  350. $result = array();
  351. $pattern = '/^STL-(\d{8,8})\.(\d{2,2})\.(.{3,3})\.CSV$/';
  352. foreach ($list as $filename => $data) {
  353. if (preg_match($pattern, $filename)) {
  354. $result[$filename] = $data;
  355. }
  356. }
  357. return $result;
  358. }
  359. }