|
|
@@ -11,34 +11,71 @@ use App\Domain\Entity\PortfolioMovementItem;
|
|
11
|
11
|
|
|
12
|
12
|
class XmlParser
|
|
13
|
13
|
{
|
|
|
14
|
+ private const XML_HEADER_AGRMT = 'ШапкаГенСог';
|
|
|
15
|
+ private const XML_HEADER_PERIOD = 'ШапкаПериод';
|
|
|
16
|
+ private const XML_PORTFOLIO_TABLE = 'ШапкаПортфель';
|
|
|
17
|
+ private const XML_PORTFOLIO_SECTION = 'ЗаголовокПортфель';
|
|
|
18
|
+ private const XML_MOVEMENTS_SECTION = 'ШапкаДвиженияИОстаткиЦБ';
|
|
|
19
|
+ private const PREFIX_DETAILS = 'Детали';
|
|
|
20
|
+
|
|
|
21
|
+ private const ATTR_CLIENT = 'Клиент';
|
|
|
22
|
+ private const ATTR_START_DATE = 'НачПериода';
|
|
|
23
|
+ private const ATTR_END_DATE = 'КонПериода';
|
|
|
24
|
+ private const ATTR_PERIOD_LINE = 'СтрокаПериода';
|
|
|
25
|
+ private const ATTR_PERIOD = 'Период';
|
|
|
26
|
+ private const ATTR_SECURITY = 'ЦБ';
|
|
|
27
|
+ private const ATTR_ISSUER = 'Эмитент';
|
|
|
28
|
+ private const ATTR_PRICE_START = 'НОЦена';
|
|
|
29
|
+ private const ATTR_PRICE_END = 'КОЦена';
|
|
|
30
|
+ private const ATTR_QTY_START = 'КоличествоНО';
|
|
|
31
|
+ private const ATTR_QTY_END = 'КоличествоКО';
|
|
|
32
|
+ private const ATTR_SUM_START = 'СуммаНКДНО';
|
|
|
33
|
+ private const ATTR_SUM_END = 'СуммаНКДКО';
|
|
|
34
|
+ private const ATTR_SUM_TOTAL = 'КОСумма';
|
|
|
35
|
+ private const ATTR_QTY_START_MV = 'НО';
|
|
|
36
|
+ private const ATTR_QTY_END_MV = 'КО';
|
|
|
37
|
+ private const ATTR_QTY_INCOME = 'Приход';
|
|
|
38
|
+ private const ATTR_QTY_OUTCOME = 'Расход';
|
|
|
39
|
+ private const DATE_FORMAT = 'd.m.Y';
|
|
|
40
|
+
|
|
14
|
41
|
public function processXml(\SimpleXMLElement $xml): ParsedPortfolio
|
|
15
|
42
|
{
|
|
16
|
43
|
return new ParsedPortfolio(
|
|
17
|
44
|
header: $this->processXmlHeader($xml),
|
|
18
|
|
- details: $this->processDetails($xml->{'ЗаголовокПортфель'}->{'ШапкаПортфель'}),
|
|
19
|
|
- movements: $this->processMovements($xml->{'ШапкаДвиженияИОстаткиЦБ'}),
|
|
|
45
|
+ details: $this->processDetails(
|
|
|
46
|
+ $xml->{self::XML_PORTFOLIO_SECTION}->{self::XML_PORTFOLIO_TABLE}
|
|
|
47
|
+ ),
|
|
|
48
|
+ movements: $this->processMovements(
|
|
|
49
|
+ $xml->{self::XML_MOVEMENTS_SECTION}
|
|
|
50
|
+ ),
|
|
20
|
51
|
);
|
|
21
|
52
|
}
|
|
22
|
53
|
|
|
23
|
54
|
private function processXmlHeader(\SimpleXMLElement $xml): PortfolioHeader
|
|
24
|
55
|
{
|
|
25
|
56
|
$attrs = [];
|
|
26
|
|
- foreach (['ШапкаГенСог', 'ШапкаПериод'] as $section) {
|
|
|
57
|
+ foreach ([self::XML_HEADER_AGRMT, self::XML_HEADER_PERIOD] as $section) {
|
|
27
|
58
|
foreach ($xml->{$section}->attributes() as $key => $value) {
|
|
28
|
59
|
$attrs[$key] = get_object_vars($value)[0];
|
|
29
|
60
|
}
|
|
30
|
61
|
}
|
|
31
|
62
|
|
|
32
|
|
- if (array_key_exists('НачПериода', $attrs)) {
|
|
33
|
|
- $startDate = \DateTimeImmutable::createFromFormat('d.m.Y', $attrs['НачПериода']);
|
|
34
|
|
- $endDate = \DateTimeImmutable::createFromFormat('d.m.Y', $attrs['КонПериода']);
|
|
35
|
|
- } elseif (array_key_exists('СтрокаПериода', $attrs)) {
|
|
36
|
|
- $chunks = explode(' ', $attrs['СтрокаПериода']);
|
|
|
63
|
+ if (array_key_exists(self::ATTR_START_DATE, $attrs)) {
|
|
|
64
|
+ $startDate = \DateTimeImmutable::createFromFormat(
|
|
|
65
|
+ self::DATE_FORMAT,
|
|
|
66
|
+ $attrs[self::ATTR_START_DATE],
|
|
|
67
|
+ );
|
|
|
68
|
+ $endDate = \DateTimeImmutable::createFromFormat(
|
|
|
69
|
+ self::DATE_FORMAT,
|
|
|
70
|
+ $attrs[self::ATTR_END_DATE],
|
|
|
71
|
+ );
|
|
|
72
|
+ } elseif (array_key_exists(self::ATTR_PERIOD_LINE, $attrs)) {
|
|
|
73
|
+ $chunks = explode(' ', $attrs[self::ATTR_PERIOD_LINE]);
|
|
37
|
74
|
if (count($chunks) !== 4) {
|
|
38
|
75
|
throw new \RuntimeException('Unexpected period format');
|
|
39
|
76
|
}
|
|
40
|
|
- $startDate = \DateTimeImmutable::createFromFormat('d.m.Y', $chunks[1]);
|
|
41
|
|
- $endDate = \DateTimeImmutable::createFromFormat('d.m.Y', $chunks[3]);
|
|
|
77
|
+ $startDate = \DateTimeImmutable::createFromFormat(self::DATE_FORMAT, $chunks[1]);
|
|
|
78
|
+ $endDate = \DateTimeImmutable::createFromFormat(self::DATE_FORMAT, $chunks[3]);
|
|
42
|
79
|
} else {
|
|
43
|
80
|
throw new \RuntimeException('Cannot detect XML header version');
|
|
44
|
81
|
}
|
|
|
@@ -48,7 +85,7 @@ class XmlParser
|
|
48
|
85
|
}
|
|
49
|
86
|
|
|
50
|
87
|
return new PortfolioHeader(
|
|
51
|
|
- clientAgreement: $attrs['Клиент'],
|
|
|
88
|
+ clientAgreement: $attrs[self::ATTR_CLIENT],
|
|
52
|
89
|
startDate: $startDate,
|
|
53
|
90
|
endDate: $endDate,
|
|
54
|
91
|
);
|
|
|
@@ -59,7 +96,7 @@ class XmlParser
|
|
59
|
96
|
$items = [];
|
|
60
|
97
|
|
|
61
|
98
|
foreach (get_object_vars($xml) as $key => $value) {
|
|
62
|
|
- if (mb_strpos($key, 'Детали') === false) {
|
|
|
99
|
+ if (mb_strpos($key, self::PREFIX_DETAILS) === false) {
|
|
63
|
100
|
continue;
|
|
64
|
101
|
}
|
|
65
|
102
|
|
|
|
@@ -74,15 +111,15 @@ class XmlParser
|
|
74
|
111
|
}
|
|
75
|
112
|
|
|
76
|
113
|
$items[] = new PortfolioDetailItem(
|
|
77
|
|
- issuer: $attr['Эмитент'],
|
|
78
|
|
- security: $attr['ЦБ'],
|
|
79
|
|
- priceStart: $attr['НОЦена'],
|
|
80
|
|
- priceEnd: $attr['КОЦена'],
|
|
81
|
|
- quantityStart: (int) $attr['КоличествоНО'],
|
|
82
|
|
- quantityEnd: (int) $attr['КоличествоКО'],
|
|
83
|
|
- sumStart: $attr['СуммаНКДНО'],
|
|
84
|
|
- sumEnd: $attr['СуммаНКДКО'],
|
|
85
|
|
- sumTotal: $attr['КОСумма'],
|
|
|
114
|
+ issuer: $attr[self::ATTR_ISSUER],
|
|
|
115
|
+ security: $attr[self::ATTR_SECURITY],
|
|
|
116
|
+ priceStart: $attr[self::ATTR_PRICE_START],
|
|
|
117
|
+ priceEnd: $attr[self::ATTR_PRICE_END],
|
|
|
118
|
+ quantityStart: (int) $attr[self::ATTR_QTY_START],
|
|
|
119
|
+ quantityEnd: (int) $attr[self::ATTR_QTY_END],
|
|
|
120
|
+ sumStart: $attr[self::ATTR_SUM_START],
|
|
|
121
|
+ sumEnd: $attr[self::ATTR_SUM_END],
|
|
|
122
|
+ sumTotal: $attr[self::ATTR_SUM_TOTAL],
|
|
86
|
123
|
);
|
|
87
|
124
|
}
|
|
88
|
125
|
}
|
|
|
@@ -95,7 +132,7 @@ class XmlParser
|
|
95
|
132
|
$items = [];
|
|
96
|
133
|
|
|
97
|
134
|
foreach (get_object_vars($xml) as $key => $value) {
|
|
98
|
|
- if (mb_strpos($key, 'Детали') === false) {
|
|
|
135
|
+ if (mb_strpos($key, self::PREFIX_DETAILS) === false) {
|
|
99
|
136
|
continue;
|
|
100
|
137
|
}
|
|
101
|
138
|
|
|
|
@@ -109,15 +146,13 @@ class XmlParser
|
|
109
|
146
|
$attr[$attrName] = get_object_vars($attrValue)[0];
|
|
110
|
147
|
}
|
|
111
|
148
|
|
|
112
|
|
- $period = new \DateTimeImmutable($attr['Период']);
|
|
113
|
|
-
|
|
114
|
149
|
$items[] = new PortfolioMovementItem(
|
|
115
|
|
- security: $attr['ЦБ'],
|
|
116
|
|
- period: $period,
|
|
117
|
|
- quantityStart: (int) $attr['НО'],
|
|
118
|
|
- quantityEnd: (int) $attr['КО'],
|
|
119
|
|
- quantityIncome: (int) $attr['Приход'],
|
|
120
|
|
- quantityOutcome:(int) $attr['Расход'],
|
|
|
150
|
+ security: $attr[self::ATTR_SECURITY],
|
|
|
151
|
+ period: new \DateTimeImmutable($attr[self::ATTR_PERIOD]),
|
|
|
152
|
+ quantityStart: (int) $attr[self::ATTR_QTY_START_MV],
|
|
|
153
|
+ quantityEnd: (int) $attr[self::ATTR_QTY_END_MV],
|
|
|
154
|
+ quantityIncome: (int) $attr[self::ATTR_QTY_INCOME],
|
|
|
155
|
+ quantityOutcome:(int) $attr[self::ATTR_QTY_OUTCOME],
|
|
121
|
156
|
);
|
|
122
|
157
|
}
|
|
123
|
158
|
}
|