Completed
Push — master ( a0f3ba...4d0a57 )
by Aimeos
03:07
created

Standard::createContext()   B

Complexity

Conditions 2
Paths 5

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 16
nc 5
nop 1
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2018
6
 * @package Controller
7
 * @subpackage Jobs
8
 */
9
10
11
namespace Aimeos\Controller\Jobs\Subscription\Process\Renew;
12
13
14
/**
15
 * Job controller for subscription processs renew.
16
 *
17
 * @package Controller
18
 * @subpackage Jobs
19
 */
20
class Standard
21
	extends \Aimeos\Controller\Jobs\Subscription\Process\Base
0 ignored issues
show
Coding Style introduced by
The extends keyword must be on the same line as the class name
Loading history...
Coding Style introduced by
Expected 0 spaces between "Base" and comma; 1 found
Loading history...
22
	implements \Aimeos\Controller\Jobs\Iface
0 ignored issues
show
Coding Style introduced by
The implements keyword must be on the same line as the class name
Loading history...
23
{
24
	/**
25
	 * Returns the localized name of the job.
26
	 *
27
	 * @return string Name of the job
28
	 */
29
	public function getName()
30
	{
31
		return $this->getContext()->getI18n()->dt( 'controller/jobs', 'Subscription process renew' );
32
	}
33
34
35
	/**
36
	 * Returns the localized description of the job.
37
	 *
38
	 * @return string Description of the job
39
	 */
40
	public function getDescription()
41
	{
42
		return $this->getContext()->getI18n()->dt( 'controller/jobs', 'Renews subscriptions at next date' );
43
	}
44
45
46
	/**
47
	 * Executes the job.
48
	 *
49
	 * @throws \Aimeos\Controller\Jobs\Exception If an error occurs
50
	 */
51
	public function run()
52
	{
53
		$context = $this->getContext();
54
		$config = $context->getConfig();
55
		$logger = $context->getLogger();
56
57
		$names = (array) $config->get( 'controller/common/subscription/process/processors', [] );
58
59
		$date = date( 'Y-m-d' );
60
		$processors = $this->getProcessors( $names );
61
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'subscription' );
62
63
		$search = $manager->createSearch( true );
64
		$expr = [
65
			$search->compare( '<', 'subscription.datenext', $date ),
66
			$search->combine( '||', [
67
				$search->compare( '==', 'subscription.dateend', null ),
68
				$search->compare( '>', 'subscription.dateend', $date ),
69
			] ),
70
			$search->getConditions(),
71
		];
72
		$search->setConditions( $search->combine( '&&', $expr ) );
73
		$search->setSortations( [$search->sort( '+', 'subscription.id' )] );
74
75
		$start = 0;
76
77
		do
78
		{
79
			$search->setSlice( $start, 100 );
80
			$items = $manager->searchItems( $search );
81
82
			foreach( $items as $item )
83
			{
84
				try
85
				{
86
					$context = $this->createContext( $item->getOrderBaseId() );
87
					$newOrder = $this->createOrderBase( $context, $item );
88
					$newInvoice = $this->createOrderInvoice( $context, $newOrder );
89
90
					$this->createPayment( $context, $newOrder, $newInvoice );
0 ignored issues
show
Bug introduced by
It seems like $newInvoice defined by $this->createOrderInvoice($context, $newOrder) on line 88 can be null; however, Aimeos\Controller\Jobs\S...andard::createPayment() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
91
92
					foreach( $processors as $processor ) {
93
						$processor->renew( $item, $newInvoice );
94
					}
95
96
					$interval = \DateInterval::createFromDateString( $item->getInterval() );
97
					$item->setDateNext( date_create( $item->getTimeCreated() )->add( $interval )->format( 'Y-m-d' ) );
98
99
					$manager->saveItem( $item );
100
				}
101
				catch( \Exception $e )
102
				{
103
					$msg = 'Unable to process subscription with ID "%1$S": %2$s';
104
					$logger->log( sprintf( $msg, $item->getId(), $e->getMessage() ) );
105
					$logger->log( $e->getTraceAsString() );
106
				}
107
			}
108
109
			$count = count( $items );
110
			$start += $count;
111
		}
112
		while( $count === $search->getSliceSize() );
113
	}
114
115
116
	/**
117
	 * Creates a new context based on the order and the customer the subscription belongs to
118
	 *
119
	 * @param string $baseId Unique order base ID
120
	 * @return \Aimeos\MShop\Context\Item\Iface New context object
121
	 */
122
	protected function createContext( $baseId )
123
	{
124
		$context = clone $this->getContext();
125
126
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'order/base' );
127
		$baseItem = $manager->getItem( $baseId );
128
129
		$locale = $baseItem->getLocale();
130
		$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
131
132
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'locale' );
133
		$locale = $manager->bootstrap( $baseItem->getSiteCode(), $locale->getLanguageId(), $locale->getCurrencyId(), false, $level );
134
135
		$context->setLocale( $locale );
136
137
		try
138
		{
139
			$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer' );
140
			$customerItem = $manager->getItem( $baseItem->getCustomerId(), ['customer/group'] );
141
142
			$context->setUserId( $baseItem->getCustomerId() );
143
			$context->setGroupIds( $customerItem->getGroups() );
144
		}
145
		catch( \Exception $e ) {} // Subscription without account
146
147
		return $context;
148
	}
149
150
151
	/**
152
	 * Creates and stores a new order for the subscribed product
153
	 *
154
	 * @param \Aimeos\MShop\Context\Item\Iface Context object
155
	 * @param \Aimeos\MShop\Subscription\Item\Iface $subscription Subscription item with order base ID and order product ID
156
	 * @return \Aimeos\MShop\Order\Item\Base\Iface Complete order with product, addresses and services saved to the storage
157
	 */
158
	protected function createOrderBase( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MShop\Subscription\Item\Iface $subscription )
159
	{
160
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'order/base' );
161
162
		$basket = $manager->load( $subscription->getOrderBaseId() );
163
164
		$newBasket = $manager->createItem();
165
		$newBasket->setCustomerId( $basket->getCustomerId() );
166
167
		foreach( $basket->getProducts() as $orderProduct )
168
		{
169
			if( $orderProduct->getId() === $subscription->getOrderProductId() ) {
170
				$newBasket->addProduct( $orderProduct );
171
			}
172
		}
173
174
		foreach( $basket->getAddresses() as $type => $orderAddress ) {
175
			$newBasket->setAddress( $orderAddress, $type );
176
		}
177
178
		foreach( $basket->getServices() as $type => $orderServices )
179
		{
180
			foreach( $orderServices as $orderService ) {
181
				$newBasket->addService( $orderService, $type );
182
			}
183
		}
184
185
		return $manager->store( $newBasket );
186
	}
187
188
189
	/**
190
	 * Creates and stores a new invoice for the given order basket
191
	 *
192
	 * @param \Aimeos\MShop\Context\Item\Iface Context object
193
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Complete order with product, addresses and services saved to the storage
194
	 * @return \Aimeos\MShop\Order\Item\Iface New invoice item associated to the order saved to the storage
195
	 */
196
	protected function createOrderInvoice( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MShop\Order\Item\Base\Iface $basket )
197
	{
198
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'order' );
199
200
		$item = $manager->createItem();
201
		$item->setBaseId( $basket->getId() );
202
		$item->setType( 'renewal');
203
204
		return $manager->saveItem( $item );
205
	}
206
207
208
	/**
209
	 * Creates a new payment for the given order and invoice
210
	 *
211
	 * @param \Aimeos\MShop\Context\Item\Iface Context object
212
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Complete order with product, addresses and services
213
	 * @param \Aimeos\MShop\Order\Item\Iface New invoice item associated to the order
214
	 */
215
	protected function createPayment( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MShop\Order\Item\Base\Iface $basket,
216
		\Aimeos\MShop\Order\Item\Iface $invoice )
217
	{
218
		$services = $basket->getService( \Aimeos\MShop\Order\Item\Base\Service\Base::TYPE_PAYMENT );
219
220
		if( ( $service = reset( $services ) ) === false ) {
221
			return;
222
		}
223
224
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'service' );
225
		$item = $manager->getItem( $service->getServiceId() );
226
		$provider = $manager->getProvider( $item, 'payment' );
227
228
		$provider->repay( $invoice );
229
	}
230
}
231