3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2018 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
29 * Class api_v3_TaxContributionPageTest
32 class api_v3_TaxContributionPageTest
extends CiviUnitTestCase
{
33 protected $_apiversion = 3;
35 protected $financialtypeID;
36 protected $financialAccountId;
37 protected $_entity = 'contribution_page';
38 protected $_priceSetParams = array();
39 protected $_paymentProcessorType;
40 protected $payParams = array();
41 protected $paymentProceParams = array();
42 protected $settingValue = array();
43 protected $setInvoiceSettings;
44 protected $_ids = array();
45 protected $_individualId;
46 protected $financialAccHalftax;
47 protected $financialtypeHalftax;
48 protected $financialRelationHalftax;
49 protected $halfFinancialAccId;
50 protected $halfFinancialTypeId;
51 public $DBResetRequired = TRUE;
53 public function setUp() {
55 $this->_individualId
= $this->individualCreate();
56 $this->_orgId
= $this->organizationCreate(NULL);
58 $this->params
= array(
59 'title' => "Test Contribution Page" . substr(sha1(rand()), 0, 7),
60 'financial_type_id' => 1,
61 'payment_processor' => 1,
65 'pay_later_text' => 'I will pay later',
66 'pay_later_receipt' => "I will pay later",
67 'is_monetary' => TRUE,
68 'is_billing_required' => TRUE,
71 $this->_priceSetParams
= array(
72 'name' => 'tax_contribution' . substr(sha1(rand()), 0, 7),
73 'title' => 'contributiontax' . substr(sha1(rand()), 0, 7),
75 'help_pre' => "Where does your goat sleep",
76 'help_post' => "thank you for your time",
78 'financial_type_id' => 3,
79 'is_quick_config' => 0,
82 // Financial Account with 20% tax rate
83 $financialAccountSetparams = array(
85 'name' => 'vat full taxrate account' . substr(sha1(rand()), 0, 7),
86 'contact_id' => $this->_orgId
,
87 'financial_account_type_id' => 2,
95 $financialAccount = $this->callAPISuccess('financial_account', 'create', $financialAccountSetparams);
96 $this->financialAccountId
= $financialAccount['id'];
98 // Financial type having 'Sales Tax Account is' with liability financail account
99 $financialType = array(
100 'name' => 'grassvariety1' . substr(sha1(rand()), 0, 7),
104 $priceField = $this->callAPISuccess('financial_type', 'create', $financialType);
105 $this->financialtypeID
= $priceField['id'];
106 $financialRelationParams = array(
107 'entity_table' => 'civicrm_financial_type',
108 'entity_id' => $this->financialtypeID
,
109 'account_relationship' => 10,
110 'financial_account_id' => $this->financialAccountId
,
112 $financialRelation = CRM_Financial_BAO_FinancialTypeAccount
::add($financialRelationParams);
114 // Financial type with 5% tax rate
115 $financialAccHalftax = array(
116 'name' => 'vat half taxrate account' . substr(sha1(rand()), 0, 7),
117 'contact_id' => $this->_orgId
,
118 'financial_account_type_id' => 2,
125 $halfFinancialAccount = CRM_Financial_BAO_FinancialAccount
::add($financialAccHalftax);
126 $this->halfFinancialAccId
= $halfFinancialAccount->id
;
127 $halfFinancialtypeHalftax = array(
128 'name' => 'grassvariety2' . substr(sha1(rand()), 0, 7),
133 $halfFinancialType = CRM_Financial_BAO_FinancialType
::add($halfFinancialtypeHalftax);
134 $this->halfFinancialTypeId
= $halfFinancialType->id
;
135 $financialRelationHalftax = array(
136 'entity_table' => 'civicrm_financial_type',
137 'entity_id' => $this->halfFinancialTypeId
,
138 'account_relationship' => 10,
139 'financial_account_id' => $this->halfFinancialAccId
,
142 $halfFinancialRelation = CRM_Financial_BAO_FinancialTypeAccount
::add($financialRelationHalftax);
144 // Enable component contribute setting
145 $setInvoiceSettings = $this->enableTaxAndInvoicing();
148 $paymentProceParams = array(
150 'name' => 'dummy' . substr(sha1(rand()), 0, 7),
151 'payment_processor_type_id' => CRM_Core_PseudoConstant
::getKey('CRM_Financial_BAO_PaymentProcessor', 'payment_processor_type_id', 'Dummy'),
152 'financial_account_id' => 12,
155 'user_name' => 'dummy',
156 'url_site' => 'http://dummy.com',
157 'url_recur' => 'http://dummyrecur.com',
158 'class_name' => 'Payment_Dummy',
163 $result = $this->callAPISuccess('payment_processor', 'create', $paymentProceParams);
164 $this->_ids
['paymentProcessID'] = $result['id'];
165 require_once 'api/v3/examples/PaymentProcessor/Create.php';
166 $this->assertAPISuccess($result);
169 public function tearDown() {
170 $this->quickCleanUpFinancialEntities();
173 public function setUpContributionPage() {
174 $contributionPageResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
175 if (empty($this->_ids
['price_set'])) {
176 $priceSet = $this->callAPISuccess('price_set', 'create', $this->_priceSetParams
);
177 $this->_ids
['price_set'][] = $priceSet['id'];
179 $priceSetID = $this->_price
= reset($this->_ids
['price_set']);
180 CRM_Price_BAO_PriceSet
::addTo('civicrm_contribution_page', $contributionPageResult['id'], $priceSetID);
182 if (empty($this->_ids
['price_field'])) {
183 $priceField = $this->callAPISuccess('price_field', 'create', array(
184 'price_set_id' => $priceSetID,
185 'label' => 'Goat Breed',
186 'html_type' => 'Radio',
188 $this->_ids
['price_field'] = array($priceField['id']);
190 if (empty($this->_ids
['price_field_value'])) {
191 $this->callAPISuccess('price_field_value', 'create', array(
192 'price_set_id' => $priceSetID,
193 'price_field_id' => $priceField['id'],
194 'label' => 'Long Haired Goat',
196 'financial_type_id' => $this->financialtypeID
,
198 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
199 'price_set_id' => $priceSetID,
200 'price_field_id' => $priceField['id'],
201 'label' => 'Shoe-eating Goat',
203 'financial_type_id' => $this->halfFinancialTypeId
,
205 $this->_ids
['price_field_value'] = array($priceFieldValue['id']);
207 $this->_ids
['contribution_page'] = $contributionPageResult['id'];
211 * Online and offline contrbution from above created contribution page.
213 * @param string $thousandSeparator
214 * punctuation used to refer to thousands.
216 * @dataProvider getThousandSeparators
218 public function testCreateContributionOnline($thousandSeparator) {
219 $this->setCurrencySeparators($thousandSeparator);
220 $this->setUpContributionPage();
222 'contact_id' => $this->_individualId
,
223 'receive_date' => '20120511',
224 'total_amount' => $this->formatMoneyInput(100.00),
225 'financial_type_id' => $this->financialtypeID
,
226 'contribution_page_id' => $this->_ids
['contribution_page'],
227 'payment_processor' => $this->_ids
['paymentProcessID'],
229 'invoice_id' => 67890,
231 'contribution_status_id' => 1,
234 $contribution = $this->callAPISuccess('contribution', 'create', $params);
235 $this->_ids
['contributionId'] = $contribution['id'];
236 $this->assertEquals($contribution['values'][$contribution['id']]['contact_id'], $this->_individualId
);
237 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 120.00);
238 $this->assertEquals($contribution['values'][$contribution['id']]['financial_type_id'], $this->financialtypeID
);
239 $this->assertEquals($contribution['values'][$contribution['id']]['trxn_id'], 12345);
240 $this->assertEquals($contribution['values'][$contribution['id']]['invoice_id'], 67890);
241 $this->assertEquals($contribution['values'][$contribution['id']]['source'], 'SSF');
242 $this->assertEquals($contribution['values'][$contribution['id']]['tax_amount'], 20);
243 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status_id'], 1);
244 $this->_checkFinancialRecords($contribution, 'online');
248 * Create contribution with chained line items.
250 * @param string $thousandSeparator
251 * punctuation used to refer to thousands.
253 * @dataProvider getThousandSeparators
255 public function testCreateContributionChainedLineItems($thousandSeparator) {
256 $this->setCurrencySeparators($thousandSeparator);
257 $this->setUpContributionPage();
259 'contact_id' => $this->_individualId
,
260 'receive_date' => '20120511',
261 'total_amount' => 400.00,
262 'financial_type_id' => $this->financialtypeID
,
264 'invoice_id' => 67890,
266 'contribution_status_id' => 1,
268 'api.line_item.create' => array(
270 'price_field_id' => $this->_ids
['price_field'],
272 'line_total' => '100',
273 'unit_price' => '100',
274 'financial_type_id' => $this->financialtypeID
,
277 'price_field_id' => $this->_ids
['price_field'],
279 'line_total' => '300',
280 'unit_price' => '300',
281 'financial_type_id' => $this->halfFinancialTypeId
,
286 $contribution = $this->callAPISuccess('contribution', 'create', $params);
288 $lineItems = $this->callAPISuccess('line_item', 'get', array(
289 'entity_id' => $contribution['id'],
290 'contribution_id' => $contribution['id'],
291 'entity_table' => 'civicrm_contribution',
294 $this->assertEquals(2, $lineItems['count']);
297 public function testCreateContributionPayLaterOnline() {
298 $this->setUpContributionPage();
300 'contact_id' => $this->_individualId
,
301 'receive_date' => '20120511',
302 'total_amount' => 100.00,
303 'financial_type_id' => $this->financialtypeID
,
304 'contribution_page_id' => $this->_ids
['contribution_page'],
307 'invoice_id' => 67890,
309 'contribution_status_id' => 2,
311 $contribution = $this->callAPISuccess('contribution', 'create', $params, __FUNCTION__
, __FILE__
);
312 $this->assertEquals($contribution['values'][$contribution['id']]['contact_id'], $this->_individualId
);
313 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 120.00);
314 $this->assertEquals($contribution['values'][$contribution['id']]['financial_type_id'], $this->financialtypeID
);
315 $this->assertEquals($contribution['values'][$contribution['id']]['trxn_id'], 12345);
316 $this->assertEquals($contribution['values'][$contribution['id']]['invoice_id'], 67890);
317 $this->assertEquals($contribution['values'][$contribution['id']]['source'], 'SSF');
318 $this->assertEquals($contribution['values'][$contribution['id']]['tax_amount'], 20);
319 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status_id'], 2);
320 $this->_checkFinancialRecords($contribution, 'payLater');
324 * Test online pending contributions.
326 * @param string $thousandSeparator
327 * punctuation used to refer to thousands.
329 * @dataProvider getThousandSeparators
331 public function testCreateContributionPendingOnline($thousandSeparator) {
332 $this->setCurrencySeparators($thousandSeparator);
333 $this->setUpContributionPage();
335 'contact_id' => $this->_individualId
,
336 'receive_date' => '20120511',
337 'total_amount' => $this->formatMoneyInput(100.00),
338 'financial_type_id' => $this->financialtypeID
,
339 'contribution_page_id' => $this->_ids
['contribution_page'],
341 'invoice_id' => 67890,
343 'contribution_status_id' => 2,
346 $contribution = $this->callAPISuccess('contribution', 'create', $params, __FUNCTION__
, __FILE__
);
347 $this->assertEquals($contribution['values'][$contribution['id']]['contact_id'], $this->_individualId
);
348 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 120.00);
349 $this->assertEquals($contribution['values'][$contribution['id']]['financial_type_id'], $this->financialtypeID
);
350 $this->assertEquals($contribution['values'][$contribution['id']]['trxn_id'], 12345);
351 $this->assertEquals($contribution['values'][$contribution['id']]['invoice_id'], 67890);
352 $this->assertEquals($contribution['values'][$contribution['id']]['source'], 'SSF');
353 $this->assertEquals($contribution['values'][$contribution['id']]['tax_amount'], 20);
354 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status_id'], 2);
355 $this->_checkFinancialRecords($contribution, 'pending');
356 $this->setCurrencySeparators($thousandSeparator);
360 * Update a contribution.
362 * Function tests that line items, financial records are updated when contribution amount is changed
364 public function testCreateUpdateContributionChangeTotal() {
365 $this->setUpContributionPage();
366 $this->contributionParams
= array(
367 'contact_id' => $this->_individualId
,
368 'receive_date' => '20120511',
369 'total_amount' => 100.00,
370 'financial_type_id' => $this->financialtypeID
,
372 'contribution_status_id' => 1,
374 $contribution = $this->callAPISuccess('contribution', 'create', $this->contributionParams
);
375 $lineItems = $this->callAPISuccess('line_item', 'getvalue', array(
376 'entity_id' => $contribution['id'],
377 'entity_table' => 'civicrm_contribution',
379 'return' => 'line_total',
381 $this->assertEquals('100.00', $lineItems);
382 $trxnAmount = $this->_getFinancialTrxnAmount($contribution['id']);
383 $this->assertEquals('120.00', $trxnAmount);
385 'id' => $contribution['id'],
386 'financial_type_id' => 1, // without tax rate i.e Donation
387 'total_amount' => '300',
389 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
391 $lineItems = $this->callAPISuccess('line_item', 'getvalue', array(
392 'entity_id' => $contribution['id'],
393 'entity_table' => 'civicrm_contribution',
395 'return' => 'line_total',
398 $this->assertEquals('300.00', $lineItems);
399 $trxnAmount = $this->_getFinancialTrxnAmount($contribution['id']);
400 $fitemAmount = $this->_getFinancialItemAmount($contribution['id']);
401 $this->assertEquals('300.00', $trxnAmount);
402 $this->assertEquals('300.00', $fitemAmount);
408 * @return null|string
410 public function _getFinancialTrxnAmount($contId) {
412 SUM( ft.total_amount ) AS total
413 FROM civicrm_financial_trxn AS ft
414 LEFT JOIN civicrm_entity_financial_trxn AS ceft ON ft.id = ceft.financial_trxn_id
415 WHERE ceft.entity_table = 'civicrm_contribution'
416 AND ceft.entity_id = {$contId}";
417 $result = CRM_Core_DAO
::singleValueQuery($query);
424 * @return null|string
426 public function _getFinancialItemAmount($contId) {
427 $lineItem = key(CRM_Price_BAO_LineItem
::getLineItems($contId, 'contribution'));
430 FROM civicrm_financial_item
431 WHERE entity_table = 'civicrm_line_item'
432 AND entity_id = {$lineItem}";
433 $result = CRM_Core_DAO
::singleValueQuery($query);
438 * @param array $params
441 public function _checkFinancialRecords($params, $context) {
442 $entityParams = array(
443 'entity_id' => $params['id'],
444 'entity_table' => 'civicrm_contribution',
446 if ($context == 'pending') {
447 $trxn = CRM_Financial_BAO_FinancialItem
::retrieveEntityFinancialTrxn($entityParams);
448 $this->assertNull($trxn, 'No Trxn to be created until IPN callback');
451 $trxn = current(CRM_Financial_BAO_FinancialItem
::retrieveEntityFinancialTrxn($entityParams));
453 'id' => $trxn['financial_trxn_id'],
455 if ($context != 'online' && $context != 'payLater') {
456 $compareParams = array(
457 'to_financial_account_id' => 6,
458 'total_amount' => 120,
462 if ($context == 'online') {
463 $compareParams = array(
464 'to_financial_account_id' => 12,
465 'total_amount' => 120,
469 elseif ($context == 'payLater') {
470 $compareParams = array(
471 'to_financial_account_id' => 7,
472 'total_amount' => 120,
476 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialTrxn', $trxnParams, $compareParams);
477 $entityParams = array(
478 'financial_trxn_id' => $trxn['financial_trxn_id'],
479 'entity_table' => 'civicrm_financial_item',
481 $entityTrxn = current(CRM_Financial_BAO_FinancialItem
::retrieveEntityFinancialTrxn($entityParams));
482 $fitemParams = array(
483 'id' => $entityTrxn['entity_id'],
485 $compareParams = array(
488 'financial_account_id' => $this->_getFinancialAccountId($this->financialtypeID
),
490 if ($context == 'payLater') {
491 $compareParams = array(
494 'financial_account_id' => $this->_getFinancialAccountId($this->financialtypeID
),
497 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialItem', $fitemParams, $compareParams);
501 * @param int $financialTypeId
504 public function _getFinancialAccountId($financialTypeId) {
505 $accountRel = key(CRM_Core_PseudoConstant
::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Income Account is' "));
507 $searchParams = array(
508 'entity_table' => 'civicrm_financial_type',
509 'entity_id' => $financialTypeId,
510 'account_relationship' => $accountRel,
514 CRM_Financial_BAO_FinancialTypeAccount
::retrieve($searchParams, $result);
515 return CRM_Utils_Array
::value('financial_account_id', $result);
519 * Test deleting a contribution.
521 * (It is unclear why this is in this class - it seems like maybe it doesn't test anything not
522 * on the contribution test class & might be copy and paste....).
524 public function testDeleteContribution() {
525 $contributionID = $this->contributionCreate(array(
526 'contact_id' => $this->_individualId
,
528 'financial_type_id' => $this->financialtypeID
,
529 'invoice_id' => 'dfsdf',
531 $this->callAPISuccess('contribution', 'delete', array('id' => $contributionID));