SepaTxInf::setPaymentId()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
namespace SKien\Sepa;
3
4
/**
5
 * Class representing a transaction.
6
 *
7
 * The class can be used for both transaction types - Sepa::CDD or Sepa::CCT.
8
 *
9
 * Mandatory properties:
10
 * - Name
11
 * - IBAN
12
 * - BIC
13
 * - ammount
14
 * - Description
15
 *
16
 * only mandatory for CDD:
17
 * - Mandate ID
18
 * - Mandate date of signature
19
 * - If no payment ID is set, an unique ID is created internaly
20
 *
21
 * > <b>Note:</b><br>
22
 * > The return values of the `getXXX()` methods can differ from the passed values
23
 * (`setXXX() / fromArray()`) since they  may have been converted too allowed charecters and
24
 * limited to a max. length.
25
 *
26
 * @package Sepa
27
 * @author Stefanius <[email protected]>
28
 * @copyright MIT License - see the LICENSE file for details
29
 */
30
class SepaTxInf
31
{
32
    use SepaHelper;
33
34
    /** @var string Type (Sepa::CDD or Sepa::CCT) */
35
    protected string $type = '';
36
    /** @var string Full name (lastname, firstname; company name; ...) */
37
    protected string $strName = '';
38
    /** @var string IBAN */
39
    protected string $strIBAN = '';
40
    /** @var string BIC */
41
    protected string $strBIC = '';
42
    /** @var string Mandate identification (only debit) */
43
    protected string $strMandateId = '';
44
    /** @var string Date when the mandate identification signed (only debit) (format YYYY-MM-DD) */
45
    protected string $strDateOfSignature = '';
46
    /** @var string Ultimate debitor name (information purpose only) */
47
    protected string $strUltimateName = '';
48
    /** @var string Payment id */
49
    protected string $strPaymentId = '';
50
    /** @var string Description */
51
    protected string $strDescription = '';
52
    /** @var float Value of the transaction in EUR */
53
    protected float $dblValue = 0.0;
54
    /** @var string purpose */
55
    protected string $strPurpose = '';
56
57
    /**
58
     * Create transaction info.
59
     * @param string $type (Sepa::CDD or Sepa::CCT)
60
     */
61
    public function __construct(string $type)
62
    {
63
        // invalid type causes E_USER_ERROR
64
        if ($this->isValidType($type)) {
65
            $this->type = $type;
66
        }
67
    }
68
69
    /**
70
     * Validate the object.
71
     * > This method usually dont have to be called from outside. It is
72
     * called, when an instance is added to a PPI!
73
     * @return int Sepa::OK or error code
74
     * @internal
75
     */
76
    public function validate() : int
77
    {
78
        $iErr = $this->validateIBAN() | $this->validateBIC() | $this->validateMandatory();
79
80
        // create payment id if empty so far!
81
        if (empty($this->strPaymentId)) {
82
            $this->strPaymentId = ($this->type == Sepa::CDD ? self::createUID() : 'NOTPROVIDED');
83
        }
84
        return $iErr;
85
    }
86
87
    /**
88
     * Get the error message for given error code.
89
     * Since a transaction info can contain multiple errors, the result may contain more than
90
     * one message separated by a separator. <br>
91
     * The separator can be specified to meet the needs of different output destinations.
92
     * Default value is a linefeed.
93
     * @param int $iError   the errorcode
94
     * @param string $strLF     Separator for multiple errors (default: PHP_EOL; posible values: '&lt;br/&gt;', ';', ...)
95
     * @return string
96
     */
97
    public function errorMsg(int $iError, string $strLF = PHP_EOL) : string
98
    {
99
        // route to the Sepa class to get localized message
100
        return Sepa::errorMsgTxInf($iError, $strLF);
101
    }
102
103
    /**
104
     * Set properties through associative array.
105
     * Example array:
106
     * ```php
107
     *   $aPPI = [
108
     *       'strName' => '<name>',
109
     *       'strIBAN' => '<IBAN>',
110
     *       'strBIC' => '<BIC>',
111
     *       'strMandateId' => '<MandateId>',
112
     *       'strDateOfSignature' => '<DateOfSignature>',
113
     *       'strDescription' => '<Description>',
114
     *       'strUltimateName' => '<UltimateName>',
115
     *       'strPaymentId' => '<PaymentId>',
116
     *       'strPurpose' => 'setPurpose',
117
     *       'dblValue' => 123.4,
118
     *   ];
119
     * ```
120
     * The array does not have to contain all of the properties. Mandatory properties
121
     * can be set later using the respective `setXXX()` method, optional ones can be left out.
122
     *
123
     * @param array<string,string|int|float> $aProperties    see description
124
     */
125
    public function fromArray(array $aProperties) : void
126
    {
127
        // use the setter methods to ensure that all validations are made!
128
        $aPropertyMap = [
129
            'strName' => 'setName',
130
            'strIBAN' => 'setIBAN',
131
            'strBIC' => 'setBIC',
132
            'strMandateId' => 'setMandateId',
133
            'strDateOfSignature' => 'setDateOfSignature',
134
            'strDescription' => 'setDescription',
135
            'strUltimateName' => 'setUltimateName',
136
            'strPaymentId' => 'setPaymentId',
137
            'strPurpose' => 'setPurpose',
138
        ];
139
        foreach ($aPropertyMap as $strKey => $strFunc) {
140
            if (isset($aProperties[$strKey])) {
141
                $this->$strFunc($aProperties[$strKey]);
142
            }
143
        }
144
        if (isset($aProperties['dblValue'])) {
145
            $this->setValue(floatval($aProperties['dblValue']));
146
        }
147
    }
148
149
    /**
150
     * Set full name (lastname, firstname; company name; ...).
151
     * @param string $strName
152
     */
153
    public function setName(string $strName) : void
154
    {
155
        $this->strName = self::validString($strName, Sepa::MAX70);
156
    }
157
158
    /**
159
     * Set the IBAN.
160
     * @param string $strIBAN
161
     */
162
    public function setIBAN(string $strIBAN) : void
163
    {
164
        $this->strIBAN = $strIBAN;
165
    }
166
167
    /**
168
     * Set the BIC.
169
     * @param string $strBIC
170
     */
171
    public function setBIC(string $strBIC) : void
172
    {
173
        $this->strBIC = $strBIC;
174
    }
175
176
    /**
177
     * Set the mandate identification (only CDD).
178
     * @param string $strMandateId
179
     */
180
    public function setMandateId(string $strMandateId) : void
181
    {
182
        $this->strMandateId = self::validString($strMandateId, Sepa::ID2);
183
    }
184
185
    /**
186
     * Set the date when the mandate identification signed (only CDD).
187
     * @param \DateTime|int|string $DateOfSignature    may be string (format YYYY-MM-DD), int (unixtimestamp) or DateTime - object
188
     */
189
    public function setDateOfSignature($DateOfSignature) : void
190
    {
191
        if (is_object($DateOfSignature) && get_class($DateOfSignature) == 'DateTime') {
192
            // DateTime -object
193
            $this->strDateOfSignature = $DateOfSignature->format('Y-m-d');
194
        } else if (is_numeric($DateOfSignature)) {
195
            $this->strDateOfSignature = date('Y-m-d', intval($DateOfSignature));
196
        } else if (is_string($DateOfSignature)) {
197
            $this->strDateOfSignature = $DateOfSignature;
198
        }
199
    }
200
201
    /**
202
     * Set ultimate debitor name (optional - information purpose only)
203
     * @param string $strUltimateName
204
     */
205
    public function setUltimateName(string $strUltimateName) : void
206
    {
207
        $this->strUltimateName = self::validString($strUltimateName, Sepa::MAX70);
208
    }
209
210
    /**
211
     * Set the payment id (only CDD).
212
     * If no payment ID set, an unique ID is created internaly.
213
     * @param string $strPaymentId
214
     */
215
    public function setPaymentId(string $strPaymentId) : void
216
    {
217
        $strPaymentId = self::validString($strPaymentId, Sepa::ID1);
218
        if (empty($strPaymentId)) {
219
            $strPaymentId = ($this->type == Sepa::CDD ? self::createUID() : 'NOTPROVIDED');
220
        }
221
        $this->strPaymentId = $strPaymentId;
222
    }
223
224
    /**
225
     * Set the description.
226
     * @param string $strDescription
227
     */
228
    public function setDescription(string $strDescription) : void
229
    {
230
        $this->strDescription = self::validString($strDescription, Sepa::MAX140);
231
    }
232
233
    /**
234
     * Set the purpose.
235
     * The purpose is an optional value!
236
     * If set, only ISO 20022 codes of the ExternalPurpose1Code list are allowed.
237
     * Referr to the actual list that is available in worksheet '11-Purpose 'of the Excel
238
     * file provided in the download at
239
     * [www.iso20022.org](https://www.iso20022.org/catalogue-messages/additional-content-messages/external-code-sets)
240
     * > <b>Attention:</b><br>
241
     * > There is no validation whether in this module nor through the provided XSD schemas for
242
     * this value. To avoid rejection of your data, you have to take care for valid values on your own.
243
     * @link ./Transaction-Purpose-Codes
244
     * @param string $strPurpose
245
     */
246
    public function setPurpose(string $strPurpose) : void
247
    {
248
        $this->strPurpose = strtoupper(substr($strPurpose, 0, 4));
249
    }
250
251
    /**
252
     * Set the value (amount) of the transaction.
253
     * @param float $dblValue
254
     */
255
    public function setValue(float $dblValue) : void
256
    {
257
        $this->dblValue = $dblValue;
258
    }
259
260
    /**
261
     * Return the transaction type.
262
     * @return string (Sepa::CDD or Sepa::CCT)
263
     */
264
    public function getType() : string
265
    {
266
        return $this->type;
267
    }
268
269
    /**
270
     * Get the full name (lastname, firstname; company name; ...).
271
     * @return string
272
     */
273
    public function getName() : string
274
    {
275
        return $this->strName;
276
    }
277
278
    /**
279
     * Get the IBAN.
280
     * @return string
281
     */
282
    public function getIBAN() : string
283
    {
284
        return $this->strIBAN;
285
    }
286
287
    /**
288
     * Get the BIC.
289
     * @return string
290
     */
291
    public function getBIC() : string
292
    {
293
        return $this->strBIC;
294
    }
295
296
    /**
297
     * Get the mandate identification.
298
     * @return string
299
     */
300
    public function getMandateId() : string
301
    {
302
        return $this->strMandateId;
303
    }
304
305
    /**
306
     * Return the date when the mandate identification signed.
307
     * @return string   (format YYYY-MM-DD)
308
     */
309
    public function getDateOfSignature() : string
310
    {
311
        return $this->strDateOfSignature;
312
    }
313
314
    /**
315
     * Get the ultimate debitor name.
316
     * @return string
317
     */
318
    public function getUltimateName() : string
319
    {
320
        return $this->strUltimateName;
321
    }
322
323
    /**
324
     * Get the payment id.
325
     * This ID can be created internaly.
326
     * @return string
327
     */
328
    public function getPaymentId() : string
329
    {
330
        return $this->strPaymentId;
331
    }
332
333
    /**
334
     * Get the description.
335
     * @return string
336
     */
337
    public function getDescription() : string
338
    {
339
        return $this->strDescription;
340
    }
341
342
    /**
343
     * Get the purpose.
344
     * @return string
345
     */
346
    public function getPurpose() : string
347
    {
348
        return $this->strPurpose;
349
    }
350
351
    /**
352
     * Get the value of the transaction.
353
     * @return float
354
     */
355
    public function getValue() : float
356
    {
357
        return $this->dblValue;
358
    }
359
360
    /**
361
     * Validate IBAN
362
     * @return int
363
     */
364
    private function validateIBAN() : int
365
    {
366
        $iErr = Sepa::OK;
367
        if (!Sepa::checkValidation(Sepa::V_NO_IBAN_VALIDATION)) {
368
            if (strlen($this->strIBAN) == 0) {
369
                $iErr |= Sepa::ERR_TX_IBAN_MISSING;
370
            } else if (Sepa::validateIBAN($this->strIBAN) != Sepa::OK) {
371
                $iErr |= Sepa::ERR_TX_INVALID_IBAN;
372
            }
373
        }
374
        return $iErr;
375
    }
376
377
    /**
378
     * Validate BIC
379
     * @return int
380
     */
381
    private function validateBIC() : int
382
    {
383
        $iErr = Sepa::OK;
384
        if (!Sepa::checkValidation(Sepa::V_NO_BIC_VALIDATION)) {
385
            if (strlen($this->strBIC) == 0) {
386
                $iErr |= Sepa::ERR_TX_BIC_MISSING;
387
            } else if (Sepa::validateBIC($this->strBIC) != Sepa::OK) {
388
                $iErr |= Sepa::ERR_TX_INVALID_BIC;
389
            }
390
        }
391
        return $iErr;
392
    }
393
394
    /**
395
     * Validate mandatory properties
396
     * @return int
397
     */
398
    private function validateMandatory() : int
399
    {
400
        $iErr = Sepa::OK;
401
        if (!Sepa::checkValidation(Sepa::V_IGNORE_MISSING_VALUE)) {
402
            if (strlen($this->strName) == 0) {
403
                $iErr |= Sepa::ERR_TX_NAME_MISSING;
404
            }
405
            if (strlen($this->strDescription) == 0) {
406
                $iErr |= Sepa::ERR_TX_DESCR_MISSING;
407
            }
408
            if ($this->dblValue <= 0.0) {
409
                $iErr |= Sepa::ERR_TX_ZERO_VALUE;
410
            }
411
412
            // additional check for debit
413
            if ($this->type == Sepa::CDD) {
414
                if (strlen($this->strMandateId) == 0) {
415
                    $iErr |= Sepa::ERR_TX_MAND_ID_MISSING;
416
                }
417
                if (strlen($this->strDateOfSignature) == 0) {
418
                    $iErr |= Sepa::ERR_TX_MAND_DOS_MISSING;
419
                } else if (!preg_match('/^([0-9]){4}-([0-9]){2}-([0-9]{2})/', $this->strDateOfSignature)) {
420
                    $iErr |= Sepa::ERR_TX_INVALID_MAND_DOS;
421
                }
422
            }
423
        }
424
        return $iErr;
425
    }
426
}