Skip to content

Commit 1869540

Browse files
author
ahuzhamberdiev
committed
feat: support cents in lead prices
1 parent 1174b48 commit 1869540

2 files changed

Lines changed: 209 additions & 12 deletions

File tree

src/AmoCRM/Models/LeadModel.php

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class LeadModel extends BaseApiModel implements
111111
protected $closestTaskAt;
112112

113113
/**
114-
* @var int
114+
* @var int|float|null
115115
*/
116116
protected $price;
117117

@@ -252,20 +252,20 @@ public function setName(string $name): self
252252
return $this;
253253
}
254254

255-
/**
256-
* @return null|int
257-
*/
258255
public function getPrice(): ?int
259256
{
260-
return $this->price;
257+
return isset($this->price) ? (int)$this->price : null;
258+
}
259+
260+
public function getPriceWithMinorUnits(): ?float
261+
{
262+
return isset($this->price) ? (float)$this->price : null;
261263
}
262264

263265
/**
264-
* @param null|int $price
265-
*
266-
* @return self
266+
* @param int|float|null $price
267267
*/
268-
public function setPrice(?int $price): self
268+
public function setPrice($price): self
269269
{
270270
$this->price = $price;
271271

@@ -744,7 +744,9 @@ public static function fromArray(array $lead): self
744744
$leadModel->setName($lead['name']);
745745
}
746746

747-
if (array_key_exists('price', $lead) && !is_null($lead['price'])) {
747+
if (array_key_exists('price_with_minor_units', $lead) && !is_null($lead['price_with_minor_units'])) {
748+
$leadModel->setPrice((float)$lead['price_with_minor_units']);
749+
} elseif (array_key_exists('price', $lead) && !is_null($lead['price'])) {
748750
$leadModel->setPrice((int)$lead['price']);
749751
}
750752

@@ -861,6 +863,7 @@ public function toArray(): array
861863
$result = [
862864
'name' => $this->getName(),
863865
'price' => $this->getPrice(),
866+
'price_with_minor_units' => $this->getPriceWithMinorUnits(),
864867
'responsible_user_id' => $this->getResponsibleUserId(),
865868
'group_id' => $this->getGroupId(),
866869
'status_id' => $this->getStatusId(),
@@ -932,8 +935,8 @@ public function toApi(?string $requestId = "0"): array
932935
$result['name'] = $this->getName();
933936
}
934937

935-
if (!is_null($this->getPrice())) {
936-
$result['price'] = $this->getPrice();
938+
if (!is_null($this->getPriceWithMinorUnits())) {
939+
$result['price'] = $this->getPriceWithMinorUnits();
937940
}
938941

939942
if (!is_null($this->getResponsibleUserId())) {
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cases\Price;
6+
7+
use AmoCRM\Exceptions\InvalidArgumentException;
8+
use AmoCRM\Models\LeadModel;
9+
use PHPUnit\Framework\TestCase;
10+
11+
class LeadPriceTest extends TestCase
12+
{
13+
public function testSetPriceWithIntegerPreservesLegacyBehaviour(): void
14+
{
15+
$lead = (new LeadModel())->setPrice(100);
16+
17+
$this->assertPriceState($lead, 100, 100.0);
18+
}
19+
20+
public function testSetPriceWithFloatExposesMinorUnitsAndTruncatesLegacyGetter(): void
21+
{
22+
$lead = (new LeadModel())->setPrice(100.5);
23+
24+
$this->assertPriceState($lead, 100, 100.5);
25+
}
26+
27+
public function testSetPriceWithSmallFractionKeepsLegacyPriceAtZero(): void
28+
{
29+
$lead = (new LeadModel())->setPrice(0.1);
30+
31+
$this->assertPriceState($lead, 0, 0.1);
32+
$this->assertSame(0, $lead->toArray()['price']);
33+
$this->assertSame(0.1, $lead->toArray()['price_with_minor_units']);
34+
$this->assertSame(0.1, $lead->toApi()['price']);
35+
}
36+
37+
public function testSetPriceWithLargeFractionDoesNotRoundLegacyPriceUp(): void
38+
{
39+
$lead = (new LeadModel())->setPrice(99999999.999);
40+
41+
$this->assertPriceState($lead, 99999999, 99999999.999);
42+
$this->assertNotSame(100000000, $lead->getPrice());
43+
$this->assertSame(99999999, $lead->toArray()['price']);
44+
$this->assertSame(99999999.999, $lead->toArray()['price_with_minor_units']);
45+
$this->assertSame(99999999.999, $lead->toApi()['price']);
46+
}
47+
48+
public function testSetPriceWithNullLeavesBothRepresentationsNull(): void
49+
{
50+
$lead = (new LeadModel())->setPrice(null);
51+
52+
$this->assertPriceState($lead, null, null);
53+
}
54+
55+
/**
56+
* @throws InvalidArgumentException
57+
*/
58+
public function testFromArrayUsesLegacyPriceWhenOnlyPriceIsProvided(): void
59+
{
60+
$this->assertPriceState(
61+
LeadModel::fromArray(['id' => 1, 'price' => 200]),
62+
200,
63+
200.0
64+
);
65+
}
66+
67+
/**
68+
* @throws InvalidArgumentException
69+
*/
70+
public function testFromArrayUsesMinorUnitsPriceWhenProvided(): void
71+
{
72+
$this->assertPriceState(
73+
LeadModel::fromArray(['id' => 1, 'price_with_minor_units' => 200.75]),
74+
200,
75+
200.75
76+
);
77+
}
78+
79+
/**
80+
* @throws InvalidArgumentException
81+
*/
82+
public function testFromArrayWithSmallFractionKeepsLegacyPriceAtZero(): void
83+
{
84+
$this->assertPriceState(
85+
LeadModel::fromArray(['id' => 1, 'price_with_minor_units' => 0.1]),
86+
0,
87+
0.1
88+
);
89+
}
90+
91+
/**
92+
* @throws InvalidArgumentException
93+
*/
94+
public function testFromArrayWithLargeFractionDoesNotRoundLegacyPriceUp(): void
95+
{
96+
$lead = LeadModel::fromArray([
97+
'id' => 1,
98+
'price_with_minor_units' => 99999999.999,
99+
]);
100+
101+
$this->assertPriceState($lead, 99999999, 99999999.999);
102+
$this->assertNotSame(100000000, $lead->getPrice());
103+
}
104+
105+
/**
106+
* @throws InvalidArgumentException
107+
*/
108+
public function testFromArrayPrefersMinorUnitsOverLegacyPrice(): void
109+
{
110+
$lead = LeadModel::fromArray([
111+
'id' => 1,
112+
'price' => 300,
113+
'price_with_minor_units' => 300.99,
114+
]);
115+
116+
$this->assertPriceState($lead, 300, 300.99);
117+
}
118+
119+
/**
120+
* @throws InvalidArgumentException
121+
*/
122+
public function testFromArrayFallsBackToLegacyPriceWhenMinorUnitsIsNull(): void
123+
{
124+
$lead = LeadModel::fromArray([
125+
'id' => 1,
126+
'price' => 400,
127+
'price_with_minor_units' => null,
128+
]);
129+
130+
$this->assertPriceState($lead, 400, 400.0);
131+
}
132+
133+
public function testToArrayIncludesBothPriceRepresentations(): void
134+
{
135+
$this->assertSame(
136+
[
137+
'name' => null,
138+
'price' => 123,
139+
'price_with_minor_units' => 123.45,
140+
'responsible_user_id' => null,
141+
'group_id' => null,
142+
'status_id' => null,
143+
'pipeline_id' => null,
144+
'loss_reason_id' => null,
145+
'source_id' => null,
146+
'created_by' => null,
147+
'updated_by' => null,
148+
'created_at' => null,
149+
'updated_at' => null,
150+
'closed_at' => null,
151+
'closest_task_at' => null,
152+
'is_deleted' => null,
153+
'custom_fields_values' => null,
154+
'score' => null,
155+
'account_id' => null,
156+
'id' => 1,
157+
],
158+
(new LeadModel())
159+
->setId(1)
160+
->setPrice(123.45)
161+
->toArray()
162+
);
163+
}
164+
165+
public function testToApiUsesMinorUnitsInPriceFieldForFloatInput(): void
166+
{
167+
$this->assertSame(
168+
['price' => 100.5, 'request_id' => '0'],
169+
(new LeadModel())->setPrice(100.5)->toApi()
170+
);
171+
}
172+
173+
public function testToApiUsesNumericPriceFieldForIntegerInput(): void
174+
{
175+
$this->assertSame(
176+
['price' => 100.0, 'request_id' => '0'],
177+
(new LeadModel())->setPrice(100)->toApi()
178+
);
179+
}
180+
181+
public function testToApiOmitsPriceWhenItWasNotSet(): void
182+
{
183+
$this->assertSame(['request_id' => '0'], (new LeadModel())->toApi());
184+
}
185+
186+
private function assertPriceState(LeadModel $lead, ?int $legacyPrice, ?float $priceWithMinorUnits): void
187+
{
188+
$this->assertSame($legacyPrice, $lead->getPrice());
189+
190+
is_null($priceWithMinorUnits)
191+
? $this->assertNull($lead->getPriceWithMinorUnits())
192+
: $this->assertSame($priceWithMinorUnits, $lead->getPriceWithMinorUnits());
193+
}
194+
}

0 commit comments

Comments
 (0)