Skip to content

Commit 4ae583b

Browse files
store credit payment
1 parent b6a5555 commit 4ae583b

File tree

9 files changed

+482
-2
lines changed

9 files changed

+482
-2
lines changed

app/base/commerce/PaymentMethods/Fake.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace App\Base\Commerce\PaymentMethods;
1515

16+
use App\App;
1617
use Degami\PHPFormsApi as FAPI;
1718
use Degami\PHPFormsApi\Containers\SeamlessContainer;
1819
use App\Base\Models\Cart;
@@ -32,6 +33,14 @@ public function getName(): string
3233
return 'Fake (Test) Payment';
3334
}
3435

36+
/**
37+
* {@inheritdoc}
38+
*/
39+
public function isActive(Cart $cart): bool
40+
{
41+
return App::getInstance()->getEnvironment()->canDebug() && parent::isActive($cart);
42+
}
43+
3544
public function getConfigurationForm(FAPI\Form $form, array &$form_state) : FAPI\Form
3645
{
3746
return $form;
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
/**
4+
* SiteBase
5+
* PHP Version 8.3
6+
*
7+
* @category CMS / Framework
8+
* @package Degami\Sitebase
9+
* @author Mirko De Grandis <degami@github.com>
10+
* @license MIT https://opensource.org/licenses/mit-license.php
11+
* @link https://github.com/degami/sitebase
12+
*/
13+
14+
namespace App\Base\Commerce\PaymentMethods;
15+
16+
use App\App;
17+
use Degami\PHPFormsApi as FAPI;
18+
use Degami\PHPFormsApi\Containers\SeamlessContainer;
19+
use App\Base\Models\Cart;
20+
use App\Base\Models\OrderStatus;
21+
use Degami\PHPFormsApi\Accessories\FormValues;
22+
use App\Base\Abstracts\Commerce\BasePaymentMethod;
23+
use App\Base\Models\StoreCredit as StoreCreditModel;
24+
25+
class StoreCredit extends BasePaymentMethod
26+
{
27+
public function getCode() : string
28+
{
29+
return 'store_credit';
30+
}
31+
32+
public function getName(): string
33+
{
34+
return 'Store Credit';
35+
}
36+
37+
/**
38+
* {@inheritdoc}
39+
*/
40+
public function isActive(Cart $cart): bool
41+
{
42+
if (!parent::isActive($cart)) {
43+
return false;
44+
}
45+
46+
$storeCredit = StoreCreditModel::getCollection()->where(['user_id' => $cart->getUserId(), 'website_id' => $cart->getWebsiteId()])->getFirst();
47+
48+
if ($storeCredit === null || $storeCredit->getCredit() <= $cart->getTotalInclTax()) {
49+
return false;
50+
}
51+
52+
return true;
53+
}
54+
55+
56+
public function getConfigurationForm(FAPI\Form $form, array &$form_state) : FAPI\Form
57+
{
58+
return $form;
59+
}
60+
61+
public function getPaymentFormFieldset(Cart $cart, FAPI\Form $form, array &$form_state) : FAPI\Interfaces\FieldsContainerInterface
62+
{
63+
/** @var SeamlessContainer $out */
64+
$out = $form->getFieldObj('store_credit', [
65+
'type' => 'seamless_container',
66+
]);
67+
68+
$storeCredit = StoreCreditModel::getCollection()->where(['user_id' => $cart->getUserId(), 'website_id' => $cart->getWebsiteId()])->getFirst()?->getCredit() ?? 0;
69+
70+
$formattedStoreCredit = App::getInstance()->getUtils()->formatPrice($storeCredit, $cart->getCurrencyCode());
71+
$out->addMarkup(App::getInstance()->getUtils()->translate('You can use your store credit to pay for this order. Your current store credit balance is: <strong>%s</strong>', [$formattedStoreCredit]));
72+
73+
return $out;
74+
}
75+
76+
/**
77+
* {@inheritdoc}
78+
*/
79+
public function executePayment(?FormValues $values, Cart $cart) : array
80+
{
81+
$status = OrderStatus::NOT_PAID;
82+
/** @var StoreCreditModel|null $storeCredit */
83+
$storeCredit = StoreCreditModel::getCollection()->where(['user_id' => $cart->getUserId(), 'website_id' => $cart->getWebsiteId()])->getFirst();
84+
85+
/** @var StoreCreditTransaction|null $transaction */
86+
$transaction = null;
87+
if ($storeCredit && $storeCredit->getCredit() >= $cart->getTotalInclTax()) {
88+
$transaction = $storeCredit->makeTransaction(-$cart->getTotalInclTax(), $cart->getOwner(), $cart->getWebsite());
89+
$status = OrderStatus::PAID;
90+
}
91+
92+
return [
93+
'status' => $status,
94+
'transaction_id' => $transaction?->getTransactionId(),
95+
'additional_data' => ['when' => time()]
96+
];
97+
}
98+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
/**
4+
* SiteBase
5+
* PHP Version 8.3
6+
*
7+
* @category CMS / Framework
8+
* @package Degami\Sitebase
9+
* @author Mirko De Grandis <degami@github.com>
10+
* @license MIT https://opensource.org/licenses/mit-license.php
11+
* @link https://github.com/degami/sitebase
12+
*/
13+
14+
namespace App\Base\Controllers\Admin\Json;
15+
16+
use Degami\Basics\Exceptions\BasicException;
17+
use App\Base\Abstracts\Controllers\AdminJsonPage;
18+
use App\Base\Controllers\Admin\Users;
19+
use App\Base\Models\Address;
20+
use App\Base\Models\User;
21+
use App\Base\Models\StoreCredit;
22+
use App\Base\Models\StoreCreditTransaction;
23+
use DI\DependencyException;
24+
use DI\NotFoundException;
25+
26+
/**
27+
* store credit for user JSON
28+
*/
29+
class UserStoreCredit extends AdminJsonPage
30+
{
31+
/**
32+
* return route path
33+
*
34+
* @return string
35+
*/
36+
public static function getRoutePath(): string
37+
{
38+
return 'json/user/{id:\d+}/store_credit';
39+
}
40+
41+
/**
42+
* {@inheritdoc}
43+
*
44+
* @return string
45+
*/
46+
public static function getAccessPermission(): string
47+
{
48+
return 'administer_users';
49+
}
50+
51+
/**
52+
* {@inheritdoc}
53+
*
54+
* @return array
55+
* @throws BasicException
56+
* @throws DependencyException
57+
* @throws NotFoundException
58+
*/
59+
protected function getJsonData(): array
60+
{
61+
$route_data = $this->getRouteData();
62+
$user = $this->containerCall([User::class, 'load'], ['id' => $route_data['id']]);
63+
64+
$transactions = []; $transactionsData = [];
65+
$storeCredits = StoreCredit::getCollection()->where(['user_id' => $user->getId()])->getItems();
66+
$creditSummary = "";
67+
68+
foreach ($storeCredits as $credit) {
69+
/** @var StoreCredit $credit */
70+
71+
$creditSummary .= "<div class=\"store-credit-summary\">" .
72+
$this->getUtils()->translate('Website', locale: $this->getCurrentLocale()) . ': ' . $credit->getWebsite()->getSiteName() . " | " .
73+
$this->getUtils()->translate("Total Credit", locale: $this->getCurrentLocale()) . ': ' . $credit->getCredit() .
74+
"</div>";
75+
76+
foreach ($credit->getTransactions()->getItems() as $transaction) {
77+
$transactionsData[] = $transaction->getData();
78+
$transactions[] = "<div class=\"store-credit-transaction\">" .
79+
$this->getUtils()->translate('Website', locale: $this->getCurrentLocale()) . ': ' . $credit->getWebsite()->getSiteName() . " | " .
80+
$this->getUtils()->translate("Transaction ID", locale: $this->getCurrentLocale()) . ': ' . $transaction->getTransactionId() . " | " .
81+
$this->getUtils()->translate("Amount", locale: $this->getCurrentLocale()) . ': ' . $transaction->getAmount() . " | " .
82+
$this->getUtils()->translate("Type", locale: $this->getCurrentLocale()) . ': ' . ($transaction->getMovementType() == StoreCreditTransaction::MOVEMENT_TYPE_INCREASE ? $this->getUtils()->translate("Increase", locale: $this->getCurrentLocale()) : $this->getUtils()->translate("Decrease", locale: $this->getCurrentLocale())) . " | " .
83+
$this->getUtils()->translate("Date", locale: $this->getCurrentLocale()) . ': ' . $transaction->getCreatedAt() .
84+
"</div>";
85+
}
86+
}
87+
88+
$userController = $this->containerMake(Users::class);
89+
$form = $userController->getForm();
90+
91+
$form->setAction($this->getUrl('admin.users') . '?user_id=' . $user->getId() . '&action=' . $this->getRequest()->query->get('action'));
92+
$form->addField(
93+
'user_id',
94+
[
95+
'type' => 'hidden',
96+
'default_value' => $user->getId(),
97+
]
98+
);
99+
100+
if (count($transactions) == 0) {
101+
$transactions[] = "<div class=\"no-transactions-message\">" . $this->getUtils()->translate("No store credit transactions found for this user.", locale: $this->getCurrentLocale()) . "</div>";
102+
}
103+
104+
return [
105+
'success' => true,
106+
'params' => $this->getRequest()->query->all(),
107+
'addresses' => $transactionsData,
108+
'html' => ($this->getRequest()->query->get('action') == 'newstorecredittransaction' ? $creditSummary."<hr /><div class=\"user-transactions\">" . implode("", $transactions) . "</div><hr /><h4>" . $this->getUtils()->translate("Add a new one") . "</h4>" : '') . $form->render(),
109+
'js' => "",
110+
];
111+
}
112+
}

app/base/controllers/Admin/Users.php

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use App\Base\Models\Role;
1919
use Degami\Basics\Exceptions\BasicException;
2020
use App\Base\Abstracts\Controllers\AdminManageModelsPage;
21+
use App\Base\Models\StoreCredit;
2122
use App\Base\Models\User;
2223
use Degami\PHPFormsApi as FAPI;
2324
use DI\DependencyException;
@@ -126,7 +127,16 @@ public function getFormDefinition(FAPI\Form $form, array &$form_state): FAPI\For
126127
$this->getUrl('crud.app.base.controllers.admin.json.useraddresses', ['id' => $this->getRequest()->query->get('user_id')]) . '?user_id=' . $this->getRequest()->query->get('user_id') . '&action=newaddress',
127128
'btn btn-sm btn-light inToolSidePanel'
128129
);
129-
130+
131+
$this->addActionLink(
132+
'storecredit-btn',
133+
'storecredit-btn',
134+
'<i class="fas fa-coins"></i> ' . $this->getUtils()->translate('Store Credit', locale: $this->getCurrentLocale()),
135+
$this->getUrl('crud.app.base.controllers.admin.json.userstorecredit', ['id' => $this->getRequest()->query->get('user_id')]) . '?user_id=' . $this->getRequest()->query->get('user_id') . '&action=newstorecredittransaction',
136+
'btn btn-sm btn-light inToolSidePanel'
137+
);
138+
139+
130140
if ($user->locked) {
131141
$this->addActionLink(
132142
'lock-btn',
@@ -331,6 +341,31 @@ public function getFormDefinition(FAPI\Form $form, array &$form_state): FAPI\For
331341
'default_value' => $this->getRequest()->query->get('address_id'),
332342
]);
333343
$this->fillConfirmationForm('Do you confirm the deletion of the selected element?', $form);
344+
break;
345+
case 'newstorecredittransaction':
346+
347+
$websites = $this->getUtils()->getWebsitesSelectOptions();
348+
349+
$form
350+
->addField('website_id', [
351+
'type' => 'select',
352+
'title' => 'Website',
353+
'default_value' => $this->getSiteData()->getCurrentWebsiteId(),
354+
'options' => $websites,
355+
'validate' => ['required'],
356+
])
357+
->addField('amount', [
358+
'type' => 'number',
359+
'title' => 'Amount',
360+
'step' => '0.01',
361+
'min' => 0,
362+
'max' => 10000,
363+
'validate' => ['required'],
364+
'default_value' => '',
365+
]);
366+
367+
$this->addSubmitButton($form);
368+
334369
break;
335370
}
336371

@@ -440,6 +475,37 @@ public function formSubmitted(FAPI\Form $form, &$form_state): mixed
440475
$this->setAdminActionLogData('Deleted user ' . $user->getId());
441476
$address->delete();
442477

478+
break;
479+
case 'newstorecredittransaction':
480+
481+
$storeCredit = StoreCredit::getCollection()
482+
->where([
483+
'user_id' => $user->getId(),
484+
'website_id' => $values['website_id'] ?? $this->getSiteData()->getCurrentWebsiteId(),
485+
])
486+
->getFirst();
487+
488+
if (!$storeCredit) {
489+
$storeCredit = new StoreCredit();
490+
$storeCredit->setUserId($user->getId())
491+
->setWebsiteId($values['website_id'] ?? $this->getSiteData()->getCurrentWebsiteId())
492+
->setCredit(0)
493+
->persist();
494+
}
495+
496+
$storeCredit->makeTransaction(
497+
$values['amount'],
498+
$user,
499+
$this->containerCall(
500+
[\App\Base\Models\Website::class, 'load'],
501+
['id' => $values['website_id'] ?? $this->getSiteData()->getCurrentWebsiteId()]
502+
)
503+
);
504+
505+
$this->setAdminActionLogData('Added store credit transaction for user ' . $user->getId());
506+
507+
$this->addSuccessFlashMessage($this->getUtils()->translate('Store credit transaction added successfully.', locale: $this->getCurrentLocale()));
508+
443509
break;
444510
}
445511

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace App\Base\Migrations;
4+
5+
use App\Base\Abstracts\Migrations\DBMigration;
6+
use Psr\Container\ContainerInterface;
7+
use Degami\SqlSchema\Index;
8+
use Degami\SqlSchema\Table;
9+
10+
class CreateStoreCreditTableMigration extends DBMigration
11+
{
12+
protected string $tableName = 'store_credit';
13+
14+
public function getName(): string
15+
{
16+
return '8.4_'.parent::getName();
17+
}
18+
19+
public function addDBTableDefinition(Table $table): Table
20+
{
21+
$table->addColumn('id', 'INT', null, ['UNSIGNED'])
22+
->addColumn('user_id', 'INT', null, ['UNSIGNED'], false)
23+
->addColumn('website_id', 'INT', null, ['UNSIGNED'], false)
24+
->addColumn('credit', 'FLOAT', null, [], true, null)
25+
->addColumn('created_at', 'TIMESTAMP', null, [], false, 'CURRENT_TIMESTAMP()')
26+
->addColumn('updated_at', 'TIMESTAMP', null, [], false, 'CURRENT_TIMESTAMP()')
27+
->addIndex(null, 'id', Index::TYPE_PRIMARY)
28+
->addForeignKey('fk_storecredit_website_id', ['website_id'], 'website', ['id'])
29+
->addForeignKey('fk_storecredit_owner_id', ['user_id'], 'user', ['id'])
30+
->setAutoIncrementColumn('id');
31+
32+
return $table;
33+
}
34+
}

0 commit comments

Comments
 (0)