PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.1.0
GiveWP – Donation Plugin and Fundraising Platform v4.1.0
4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 All 253 releases
give / src / Subscriptions / Models / Subscription.php
Subscription.php
322 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Give\Subscriptions\Models;
4
5 use DateTime;
6 use Exception;
7 use Give\Donations\Models\Donation;
8 use Give\Donors\Models\Donor;
9 use Give\Framework\Models\Contracts\ModelCrud;
10 use Give\Framework\Models\Contracts\ModelHasFactory;
11 use Give\Framework\Models\Model;
12 use Give\Framework\Models\ModelQueryBuilder;
13 use Give\Framework\Models\ValueObjects\Relationship;
14 use Give\Framework\PaymentGateways\PaymentGateway;
15 use Give\Framework\Support\ValueObjects\Money;
16 use Give\Subscriptions\Actions\GenerateNextRenewalForSubscription;
17 use Give\Subscriptions\DataTransferObjects\SubscriptionQueryData;
18 use Give\Subscriptions\Factories\SubscriptionFactory;
19 use Give\Subscriptions\ValueObjects\SubscriptionMode;
20 use Give\Subscriptions\ValueObjects\SubscriptionPeriod;
21 use Give\Subscriptions\ValueObjects\SubscriptionStatus;
22
23 /**
24 * Class Subscription
25 *
26 * @since 2.23.0 added the renewsAt property
27 * @since 2.19.6
28 *
29 * @property int $id
30 * @property int $donationFormId
31 * @property DateTime $createdAt
32 * @property DateTime $renewsAt The date the subscription will renew next
33 * @property int $donorId
34 * @property SubscriptionPeriod $period
35 * @property int $frequency
36 * @property int $installments The total number of installments for the subscription; discontinues after this number of installments
37 * @property string $transactionId
38 * @property SubscriptionMode $mode
39 * @property Money $amount
40 * @property Money $feeAmountRecovered
41 * @property SubscriptionStatus $status
42 * @property string $gatewayId
43 * @property string $gatewaySubscriptionId
44 * @property Donor $donor
45 * @property Donation[] $donations
46 */
47 class Subscription extends Model implements ModelCrud, ModelHasFactory
48 {
49 /**
50 * @inheritdoc
51 */
52 protected $properties = [
53 'id' => 'int',
54 'donationFormId' => 'int',
55 'createdAt' => DateTime::class,
56 'renewsAt' => DateTime::class,
57 'donorId' => 'int',
58 'period' => SubscriptionPeriod::class,
59 'frequency' => 'int',
60 'installments' => ['int', 0],
61 'transactionId' => 'string',
62 'mode' => SubscriptionMode::class,
63 'amount' => Money::class,
64 'feeAmountRecovered' => Money::class,
65 'status' => SubscriptionStatus::class,
66 'gatewaySubscriptionId' => ['string', ''],
67 'gatewayId' => 'string',
68 ];
69
70 /**
71 * @inheritdoc
72 */
73 protected $relationships = [
74 'donor' => Relationship::BELONGS_TO,
75 'donations' => Relationship::HAS_MANY,
76 ];
77
78 /**
79 * Find subscription by ID
80 *
81 * @since 2.19.6
82 *
83 * @param int $id
84 *
85 * @return Subscription|null
86 */
87 public static function find($id)
88 {
89 return give()->subscriptions->getById($id);
90 }
91
92 /**
93 * @since 2.19.6
94 *
95 * @return ModelQueryBuilder<Donor>
96 */
97 public function donor(): ModelQueryBuilder
98 {
99 return give()->donors->queryById($this->donorId);
100 }
101
102 /**
103 * @since 2.19.6
104 *
105 * @return ModelQueryBuilder<Donation>
106 */
107 public function donations(): ModelQueryBuilder
108 {
109 return give()->donations->queryBySubscriptionId($this->id);
110 }
111
112 /**
113 * Get Subscription notes
114 *
115 * @since 2.19.6
116 *
117 * @return object[]
118 */
119 public function getNotes(): array
120 {
121 return give()->subscriptions->getNotesBySubscriptionId($this->id);
122 }
123
124 /**
125 * Returns the subscription amount the donor "intended", which means it is the amount without recovered fees. So if the
126 * donor paid $100, but the donation was charged $105 with a $5 fee, this method will return $100.
127 *
128 * @since 2.20.0
129 */
130 public function intendedAmount(): Money
131 {
132 return $this->feeAmountRecovered === null
133 ? $this->amount
134 : $this->amount->subtract($this->feeAmountRecovered);
135 }
136
137 /**
138 * Bumps the subscription's renewsAt date to the next renewal date.
139 *
140 * @return void
141 */
142 public function bumpRenewalDate()
143 {
144 $this->renewsAt = give(GenerateNextRenewalForSubscription::class)(
145 $this->period,
146 $this->frequency,
147 $this->renewsAt
148 );
149 }
150
151 /**
152 * Returns the donation that began the subscription.
153 *
154 * @since 2.23.0
155 */
156 public function initialDonation(): Donation
157 {
158 return Donation::find(give()->subscriptions->getInitialDonationId($this->id));
159 }
160
161 /**
162 * @since 2.20.0 return mutated model instance
163 * @since 2.19.6
164 *
165 * @throws Exception
166 */
167 public static function create(array $attributes): Subscription
168 {
169 $subscription = new static($attributes);
170 $subscription->save();
171
172 return $subscription;
173 }
174
175 /**
176 * @since 3.20.0
177 * @throws Exception
178 */
179 public function createRenewal(array $attributes = []): Donation
180 {
181 return give()->subscriptions->createRenewal($this, $attributes);
182 }
183
184 /**
185 * @since 3.20.0
186 */
187 public function shouldCreateRenewal(): bool
188 {
189 if (!$this->status->isActive()) {
190 return false;
191 }
192
193 return $this->isIndefinite() || $this->totalDonations() < $this->installments;
194 }
195
196 /**
197 * @since 3.20.0
198 */
199 public function totalDonations(): int
200 {
201 return $this->donations()->count();
202 }
203
204 /**
205 * @since 3.20.0
206 */
207 public function shouldEndSubscription(): bool
208 {
209 if ($this->isIndefinite()) {
210 return false;
211 }
212
213 return $this->totalDonations() >= $this->installments;
214 }
215
216 /**
217 * @since 2.20.0 mutate model in repository and return void
218 * @since 2.19.6
219 *
220 * @return void
221 * @throws Exception
222 */
223 public function save()
224 {
225 if (!$this->id) {
226 give()->subscriptions->insert($this);
227 } else {
228 give()->subscriptions->update($this);
229 }
230 }
231
232 /**
233 * @since 2.19.6
234 *
235 * @throws Exception
236 */
237 public function delete(): bool
238 {
239 return give()->subscriptions->delete($this);
240 }
241
242 /**
243 * @since 2.20.0
244 *
245 * @param bool $force Set to true to ignore the status of the subscription
246 *
247 * @throws Exception
248 */
249 public function cancel(bool $force = false)
250 {
251 if (!$force && $this->status->isCancelled()) {
252 return;
253 }
254
255 $this->gateway()->cancelSubscription($this);
256 }
257
258 /**
259 * @since 2.24.0
260 */
261 public function isIndefinite(): bool
262 {
263 return $this->installments === 0;
264 }
265
266 /**
267 * @since 2.24.0
268 *
269 * @return int|float
270 */
271 public function remainingInstallments()
272 {
273 return $this->isIndefinite() ? INF : ($this->installments - $this->donations()->count());
274 }
275
276 /**
277 * @since 2.24.0
278 *
279 * @return boolean
280 */
281 public function hasExceededTheMaxInstallments(): bool
282 {
283 return 0 > $this->remainingInstallments();
284 }
285
286 /**
287 * @since 2.19.6
288 *
289 * @return ModelQueryBuilder<Subscription>
290 */
291 public static function query(): ModelQueryBuilder
292 {
293 return give()->subscriptions->prepareQuery();
294 }
295
296 /**
297 * @since 2.19.6
298 *
299 * @param object $object
300 */
301 public static function fromQueryBuilderObject($object): Subscription
302 {
303 return SubscriptionQueryData::fromObject($object)->toSubscription();
304 }
305
306 /**
307 * @return PaymentGateway
308 */
309 public function gateway(): PaymentGateway
310 {
311 return give()->gateways->getPaymentGateway($this->gatewayId);
312 }
313
314 /**
315 * @since 2.19.6
316 */
317 public static function factory(): SubscriptionFactory
318 {
319 return new SubscriptionFactory(static::class);
320 }
321 }
322