Completed
Push — master ( 0b205b...bde6a0 )
by
unknown
10:16
created

FillClosedAtField::execute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 4
rs 10
c 1
b 1
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace OroCRM\Bundle\SalesBundle\Migrations\Schema\v1_25_2;
4
5
use Psr\Log\LoggerInterface;
6
7
use Doctrine\DBAL\Platforms\MySqlPlatform;
8
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
9
use Doctrine\DBAL\Connection;
10
use Doctrine\DBAL\Types\Type;
11
12
use Oro\Bundle\MigrationBundle\Migration\ArrayLogger;
13
use Oro\Bundle\MigrationBundle\Migration\ParametrizedMigrationQuery;
14
use Oro\Bundle\MigrationBundle\Exception\UnsupportedDatabasePlatformException;
15
16
use OroCRM\Bundle\SalesBundle\Entity\Opportunity;
17
18
class FillClosedAtField extends ParametrizedMigrationQuery
19
{
20
    /**
21
     * {@inheritdoc}
22
     */
23
    public function getDescription()
24
    {
25
        $logger = new ArrayLogger();
26
        $this->doExecute($logger, true);
27
28
        return $logger->getMessages();
29
    }
30
31
    /**
32
     * {@inheritdoc}
33
     */
34
    public function execute(LoggerInterface $logger)
35
    {
36
        $this->doExecute($logger);
37
    }
38
39
    /**
40
     * @param LoggerInterface $logger
41
     * @param bool            $dryRun
42
     */
43
    protected function doExecute(LoggerInterface $logger, $dryRun = false)
44
    {
45
        $this->updateOpportunityClosedAtValue($logger, $dryRun);
46
        $this->insertClosedAtAuditData($logger, $dryRun);
47
    }
48
49
    /**
50
     * @param LoggerInterface $logger
51
     * @param bool            $dryRun
52
     */
53
    protected function insertClosedAtAuditData(LoggerInterface $logger, $dryRun)
54
    {
55
        $auditInsertSql = <<<SQL
56
INSERT INTO oro_audit_field
57
(audit_id, field, data_type, new_datetime)
58
SELECT
59
    a.id AS audit_id,
60
    'closedAt' AS field,
61
    'datetime' AS data_type,
62
    (
63
        CASE
64
            WHEN af.new_text IN (:statuses) THEN a.logged_at
65
            ELSE NULL
66
        END
67
    ) AS new_datetime
68
FROM oro_audit_field af
69
JOIN oro_audit a ON a.id = af.audit_id
70
INNER JOIN
71
(
72
    SELECT MAX(af1.id) id FROM oro_audit_field af1 JOIN oro_audit a1 ON a1.id = af1.audit_id WHERE
73
        a1.object_class = :objectClass
74
        AND af1.field = :field
75
                AND
76
            (
77
                af1.old_text IN (:statuses)
78
                OR
79
                af1.new_text IN (:statuses)
80
            )
81
        GROUP BY a1.object_id
82
) af1 ON af1.id = af.id
83
GROUP BY object_id, a.id, af.new_text
84
SQL;
85
        $params         = [
86
            'field'       => 'status',
87
            'statuses'    => ['Closed Lost', 'Closed Won', 'Lost', 'Won'],
88
            'objectClass' => 'OroCRM\Bundle\SalesBundle\Entity\Opportunity'
89
        ];
90
        $types          = [
91
            'field'       => Type::STRING,
92
            'statuses'    => Connection::PARAM_STR_ARRAY,
93
            'objectClass' => Type::STRING
94
        ];
95
96
        $this->logQuery($logger, $auditInsertSql, $params, $types);
97
98
        if (!$dryRun) {
99
            $this->connection->executeUpdate($auditInsertSql, $params, $types);
100
        }
101
    }
102
103
    /**
104
     * @param LoggerInterface $logger
105
     * @param bool            $dryRun
106
     *
107
     * @throws UnsupportedDatabasePlatformException
108
     */
109
    protected function updateOpportunityClosedAtValue(LoggerInterface $logger, $dryRun)
110
    {
111
        $platform = $this->connection->getDatabasePlatform();
112
113
        if ($platform instanceof PostgreSqlPlatform) {
114
            $updateSql = <<<SQL
115
UPDATE orocrm_sales_opportunity o
116
SET closed_at = afm.logged_at
117
FROM 
118
oro_audit a
119
INNER JOIN
120
(
121
    SELECT
122
    MAX(af.audit_id) AS max_audit_id,
123
    MAX(am.logged_at) AS logged_at
124
    FROM oro_audit_field af
125
    INNER JOIN oro_audit am ON am.id = af.audit_id AND am.object_class = :objectClass
126
    WHERE af.field = :field AND af.new_text IN (:statuses)
127
    GROUP BY am.object_id
128
) afm
129
ON afm.max_audit_id = a.id
130
131
WHERE o.status_id IN (:status_ids) and 
132
a.object_id = o.id AND a.object_class = :objectClass
133
SQL;
134
        } elseif ($platform instanceof MySqlPlatform) {
135
            $updateSql = <<<SQL
136
UPDATE orocrm_sales_opportunity o
137
INNER JOIN oro_audit a ON a.object_id = o.id AND a.object_class = :objectClass
138
INNER JOIN
139
(
140
    SELECT
141
    MAX(af.audit_id) AS max_audit_id,
142
    MAX(am.logged_at) AS logged_at
143
    FROM oro_audit_field af
144
    INNER JOIN oro_audit am ON am.id = af.audit_id AND am.object_class = :objectClass
145
    WHERE af.field = :field AND af.new_text IN (:statuses)
146
    GROUP BY am.object_id
147
) afm
148
ON afm.max_audit_id = a.id
149
SET o.closed_at = afm.logged_at
150
WHERE o.status_id IN (:status_ids)
151
SQL;
152
        } else {
153
            throw new UnsupportedDatabasePlatformException(
154
                sprintf('Platform %s is not supported', $platform->getName())
155
            );
156
        }
157
        $params = [
158
            'field'       => 'status',
159
            'statuses'    => ['Closed Lost', 'Closed Won', 'Lost', 'Won'],
160
            'objectClass' => 'OroCRM\Bundle\SalesBundle\Entity\Opportunity',
161
            'status_ids'  => [Opportunity::STATUS_WON, Opportunity::STATUS_LOST]
162
        ];
163
        $types  = [
164
            'field'       => Type::STRING,
165
            'statuses'    => Connection::PARAM_STR_ARRAY,
166
            'objectClass' => Type::STRING,
167
            'status_ids'  => Connection::PARAM_STR_ARRAY
168
        ];
169
170
        $this->logQuery($logger, $updateSql, $params, $types);
171
172
        if (!$dryRun) {
173
            $this->connection->executeUpdate($updateSql, $params, $types);
174
        }
175
    }
176
}
177