Skip to content

Commit 3982118

Browse files
committed
Add type field to invoice sequences and update related logic
1 parent ff5ed37 commit 3982118

File tree

7 files changed

+135
-18
lines changed

7 files changed

+135
-18
lines changed

config/doctrine/InvoiceSequence.orm.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
<field name="index" column="idx" type="integer" />
1313
<field name="version" type="integer" version="true" />
1414
<field name="year" type="integer" nullable="true"/>
15-
<field name="month" type="integer"/>
16-
15+
<field name="month" type="integer" nullable="true"/>
16+
<field name="type" enum-type="Sylius\InvoicingPlugin\Enum\InvoiceSequenceScopeEnum" nullable="true" />
1717
</mapped-superclass>
1818

1919
</doctrine-mapping>

src/Entity/InvoiceSequence.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
namespace Sylius\InvoicingPlugin\Entity;
1515

16+
use Sylius\InvoicingPlugin\Enum\InvoiceSequenceScopeEnum;
17+
1618
/** @final */
1719
class InvoiceSequence implements InvoiceSequenceInterface
1820
{
@@ -23,9 +25,11 @@ class InvoiceSequence implements InvoiceSequenceInterface
2325

2426
protected ?int $version = 1;
2527

26-
protected ?int $year;
28+
protected ?InvoiceSequenceScopeEnum $type = null;
29+
30+
protected ?int $year = null;
2731

28-
protected ?int $month;
32+
protected ?int $month = null;
2933

3034
/** @return mixed */
3135
public function getId()
@@ -53,6 +57,16 @@ public function setVersion(?int $version): void
5357
$this->version = $version;
5458
}
5559

60+
public function getType(): ?InvoiceSequenceScopeEnum
61+
{
62+
return $this->type;
63+
}
64+
65+
public function setType(?InvoiceSequenceScopeEnum $type): void
66+
{
67+
$this->type = $type;
68+
}
69+
5670
public function getYear(): ?int
5771
{
5872
return $this->year;

src/Entity/InvoiceSequenceInterface.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,18 @@
1515

1616
use Sylius\Component\Resource\Model\ResourceInterface;
1717
use Sylius\Component\Resource\Model\VersionedInterface;
18+
use Sylius\InvoicingPlugin\Enum\InvoiceSequenceScopeEnum;
1819

1920
interface InvoiceSequenceInterface extends ResourceInterface, VersionedInterface
2021
{
2122
public function getIndex(): int;
2223

2324
public function incrementIndex(): void;
2425

26+
public function getType(): ?InvoiceSequenceScopeEnum;
27+
28+
public function setType(?InvoiceSequenceScopeEnum $type): void;
29+
2530
public function getYear(): ?int;
2631

2732
public function getMonth(): ?int;

src/Enum/InvoiceSequenceScopeEnum.php

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,4 @@ enum InvoiceSequenceScopeEnum: string
1818
case GLOBAL = 'global';
1919
case MONTHLY = 'monthly';
2020
case ANNUALLY = 'annually';
21-
22-
public static function fromString(?string $value): self
23-
{
24-
return match ($value) {
25-
'monthly' => self::MONTHLY,
26-
'annually' => self::ANNUALLY,
27-
default => self::GLOBAL,
28-
};
29-
}
3021
}

src/Generator/SequentialInvoiceNumberGenerator.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,11 @@ private function getSequence(): InvoiceSequenceInterface
7474
InvoiceSequenceScopeEnum::MONTHLY => [
7575
'year' => (int) $now->format('Y'),
7676
'month' => (int) $now->format('m'),
77+
'type' => $scope->value,
7778
],
7879
InvoiceSequenceScopeEnum::ANNUALLY => [
7980
'year' => (int) $now->format('Y'),
81+
'type' => $scope->value,
8082
],
8183
InvoiceSequenceScopeEnum::GLOBAL => [
8284
'year' => null,
@@ -102,6 +104,10 @@ private function getSequence(): InvoiceSequenceInterface
102104
$sequence->setMonth($criteria['month']);
103105
}
104106

107+
if (isset($criteria['type'])) {
108+
$sequence->setType($criteria['type']);
109+
}
110+
105111
$this->sequenceManager->persist($sequence);
106112

107113
return $sequence;

src/Migrations/Version20251021074051.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ final class Version20251021074051 extends AbstractMigration
2020
{
2121
public function getDescription(): string
2222
{
23-
return 'Add year and month columns to sylius_invoicing_plugin_sequence table';
23+
return 'Add year, month and type columns to sylius_invoicing_plugin_sequence table';
2424
}
2525

2626
public function up(Schema $schema): void
2727
{
28-
$this->addSql('ALTER TABLE sylius_invoicing_plugin_sequence ADD year INT DEFAULT NULL, ADD month INT NOT NULL');
28+
$this->addSql('ALTER TABLE sylius_invoicing_plugin_sequence ADD year INT DEFAULT NULL, ADD month INT DEFAULT NULL, ADD type VARCHAR(255) DEFAULT NULL');
2929
}
3030

3131
public function down(Schema $schema): void
3232
{
33-
$this->addSql('ALTER TABLE sylius_invoicing_plugin_sequence DROP year, DROP month');
33+
$this->addSql('ALTER TABLE sylius_invoicing_plugin_sequence DROP year, DROP month, DROP type');
3434
}
3535
}

tests/Unit/Generator/SequentialInvoiceNumberGeneratorTest.php

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ public function it_generates_invoice_number_with_monthly_scope(): void
148148

149149
$this->sequenceRepository
150150
->method('findOneBy')
151-
->with(['year' => 2025, 'month' => 10])
151+
->with(['year' => 2025, 'month' => 10, 'type' => 'monthly'])
152152
->willReturn($sequence);
153153

154154
$sequence->method('getVersion')->willReturn(1);
@@ -188,7 +188,7 @@ public function it_generates_invoice_number_with_annually_scope(): void
188188

189189
$this->sequenceRepository
190190
->method('findOneBy')
191-
->with(['year' => 2025])
191+
->with(['year' => 2025, 'type' => 'annually'])
192192
->willReturn($sequence);
193193

194194
$sequence->method('getVersion')->willReturn(1);
@@ -207,4 +207,105 @@ public function it_generates_invoice_number_with_annually_scope(): void
207207

208208
self::assertSame('2025/11/000000001', $result);
209209
}
210+
211+
#[Test]
212+
public function it_generates_invoice_number_when_monthly_sequence_is_null(): void
213+
{
214+
$sequence = $this->createMock(InvoiceSequenceInterface::class);
215+
216+
$dateTime = new \DateTimeImmutable('2025-10-15');
217+
$this->clock->method('now')->willReturn($dateTime);
218+
219+
$generator = new SequentialInvoiceNumberGenerator(
220+
$this->sequenceRepository,
221+
$this->sequenceFactory,
222+
$this->sequenceManager,
223+
$this->clock,
224+
1,
225+
9,
226+
'monthly'
227+
);
228+
229+
$this->sequenceRepository
230+
->expects(self::once())
231+
->method('findOneBy')
232+
->with(['year' => 2025, 'month' => 10, 'type' => 'monthly'])
233+
->willReturn(null);
234+
235+
$this->sequenceFactory->expects(self::once())->method('createNew')->willReturn($sequence);
236+
$sequence->expects(self::once())->method('setYear')->with(2025);
237+
$sequence->expects(self::once())->method('setMonth')->with(10);
238+
$sequence->expects(self::once())->method('setType')->with('monthly');
239+
240+
$this->sequenceManager
241+
->expects(self::once())
242+
->method('persist')
243+
->with($sequence);
244+
245+
$sequence->method('getVersion')->willReturn(1);
246+
$sequence->method('getIndex')->willReturn(0);
247+
248+
$this->sequenceManager
249+
->expects(self::once())
250+
->method('lock')
251+
->with($sequence, LockMode::OPTIMISTIC, 1);
252+
253+
$sequence
254+
->expects(self::once())
255+
->method('incrementIndex');
256+
257+
$result = $generator->generate();
258+
259+
self::assertSame('2025/10/000000001', $result);
260+
}
261+
262+
#[Test]
263+
public function it_generates_invoice_number_when_annually_sequence_is_null(): void
264+
{
265+
$sequence = $this->createMock(InvoiceSequenceInterface::class);
266+
267+
$dateTime = new \DateTimeImmutable('2025-11-15');
268+
$this->clock->method('now')->willReturn($dateTime);
269+
270+
$generator = new SequentialInvoiceNumberGenerator(
271+
$this->sequenceRepository,
272+
$this->sequenceFactory,
273+
$this->sequenceManager,
274+
$this->clock,
275+
1,
276+
9,
277+
'annually'
278+
);
279+
280+
$this->sequenceRepository
281+
->expects(self::once())
282+
->method('findOneBy')
283+
->with(['year' => 2025, 'type' => 'annually'])
284+
->willReturn(null);
285+
286+
$this->sequenceFactory->expects(self::once())->method('createNew')->willReturn($sequence);
287+
$sequence->expects(self::once())->method('setYear')->with(2025);
288+
$sequence->expects(self::once())->method('setType')->with('monthly');
289+
290+
$this->sequenceManager
291+
->expects(self::once())
292+
->method('persist')
293+
->with($sequence);
294+
295+
$sequence->method('getVersion')->willReturn(1);
296+
$sequence->method('getIndex')->willReturn(0);
297+
298+
$this->sequenceManager
299+
->expects(self::once())
300+
->method('lock')
301+
->with($sequence, LockMode::OPTIMISTIC, 1);
302+
303+
$sequence
304+
->expects(self::once())
305+
->method('incrementIndex');
306+
307+
$result = $generator->generate();
308+
309+
self::assertSame('2025/11/000000001', $result);
310+
}
210311
}

0 commit comments

Comments
 (0)