Passed
Push — develop ( d5179e...bede24 )
by Портнов
05:56 queued 11s
created

ActionDialAnswer::fillAnsweredCdr()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 45
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 29
c 1
b 0
f 0
dl 0
loc 45
rs 8.5226
cc 7
nc 8
nop 3
1
<?php
2
3
4
namespace MikoPBX\Core\Workers\Libs\WorkerCallEvents;
5
6
7
use MikoPBX\Common\Models\CallDetailRecordsTmp;
8
use MikoPBX\Core\System\MikoPBXConfig;
9
use MikoPBX\Core\System\Util;
10
use MikoPBX\Core\Workers\WorkerCallEvents;
11
12
class ActionDialAnswer {
13
    private const NEED_CONTINUE = 1;
14
    private const NEED_BREAK    = 2;
15
    private const NORM_EXIT     = 0;
16
17
    public static function execute(WorkerCallEvents $worker, $data):void
18
    {
19
        $mikoPBXConfig = new MikoPBXConfig();
20
        $pickupexten   = $mikoPBXConfig->getGeneralSettings('PBXFeaturePickupExten');
21
        if (trim($data['dnid']) === $pickupexten) {
22
            // Pickup / перехват вызова.
23
            // Событие возникает, когда мы пытаемся перехватить вызов на соседний телефон.
24
            self::fillPickUpCdr($worker, $data);
25
        } else {
26
            self::checkSmartIvrCalls($data);
27
            $filter = self::getCallDataFilter($data);
28
29
            // Отмечаем вызов как отвеченный.
30
            $m_data = CallDetailRecordsTmp::find($filter);
31
            foreach ($m_data as $row) {
32
                $result = self::fillAnsweredCdr($worker, $data, $row);
33
                if ($result === self::NEED_BREAK) {
34
                    break;
35
                }
36
37
                if($result === self::NEED_CONTINUE) {
38
                    continue;
39
                }
40
            }
41
        }
42
    }
43
44
    /**
45
     * Возвращает фильтр по текущим CDR.
46
     * @param $data
47
     * @return array
48
     */
49
    private static function getCallDataFilter($data):array{
50
        if (isset($data['org_id'])) {
51
            // Вероятно необходимо переопределить искать по двум ID.
52
            // Применимо только для Originate, когда в качестве звонящего используем два канала
53
            // мобильный и внутренний номер.
54
            $filter = [
55
                '(UNIQUEID=:UNIQUEID: OR UNIQUEID=:org_id:) AND answer = "" AND endtime = ""',
56
                'bind' => [
57
                    'UNIQUEID' => $data['id'],
58
                    'org_id'   => $data['org_id'],
59
                ],
60
            ];
61
        } else {
62
            $filter = [
63
                '(UNIQUEID=:UNIQUEID: OR UNIQUEID=:UNIQUEID_CHAN:) AND answer = "" AND endtime = ""',
64
                'bind' => [
65
                    'UNIQUEID'      => $data['id'],
66
                    'UNIQUEID_CHAN' => $data['id'] . '_' . $data['agi_channel'],
67
                ],
68
            ];
69
        }
70
71
        return $filter;
72
    }
73
74
    /**
75
     * Проверка параметров SmartIVR звонка.
76
     * @param $data
77
     */
78
    private static function checkSmartIvrCalls($data):void
79
    {
80
        if ( empty($data['ENDCALLONANSWER'])) {
81
            return;
82
        }
83
        // Переменная ENDCALLONANSWER устанавливается при начале работы умной маршуртизации.
84
        // Как только произошел ответ на вызов, отметим вызов на приложение как завершенный.
85
        $filter = [
86
            'UNIQUEID<>:UNIQUEID: AND is_app=1 AND endtime = "" AND src_chan=:src_chan:',
87
            'bind' => [
88
                'UNIQUEID' => $data['id'],
89
                'src_chan' => $data['BRIDGEPEER'],
90
            ],
91
        ];
92
        /** @var CallDetailRecordsTmp $m_data */
93
        /** @var CallDetailRecordsTmp $row */
94
        $m_data = CallDetailRecordsTmp::find($filter);
95
        foreach ($m_data as $row) {
96
            $row->writeAttribute('endtime', $data['answer']);
97
            $row->writeAttribute('is_app', 1);
98
            $res = $row->save();
99
            if ( ! $res) {
100
                Util::sysLogMsg('ENDCALLONANSWER', implode(' ', $row->getMessages()), LOG_DEBUG);
101
            }
102
        }
103
    }
104
105
    /**
106
     * Обработка PickUp звонка.
107
     * @param $worker
108
     * @param $data
109
     */
110
    private static function fillPickUpCdr($worker, $data):void
111
    {
112
        // Pickup / перехват вызова.
113
        // Событие возникает, когда мы пытаемся перехватить вызов на соседний телефон.
114
        $filter = [
115
            'UNIQUEID=:UNIQUEID:',
116
            'bind' => ['UNIQUEID' => $data['old_id'],],
117
        ];
118
        /** @var CallDetailRecordsTmp $m_data */
119
        $m_data = CallDetailRecordsTmp::find($filter);
120
        if (count($m_data->toArray()) === 1) {
121
            /** @var CallDetailRecordsTmp $m_row_data */
122
            $m_row_data                 = $m_data[0];
123
            $new_data                   = $m_row_data->toArray();
124
            $new_data['start']          = $data['answer'];
125
            $new_data['answer']         = $data['answer'];
126
            $new_data['endtime']        = '';
127
            $new_data['dst_chan']       = $data['agi_channel'];
128
            $new_data['dst_num']        = $data['dst_num'];
129
            $new_data['UNIQUEID']       = $data['id'];
130
            $new_data['recordingfile']  = $worker->MixMonitor($new_data['dst_chan'],  'pickup_'.$new_data['UNIQUEID']);
131
132
            unset($new_data['id'], $new_data['end']);
133
            InsertDataToDB::execute($new_data);
134
            /**
135
             * Отправка UserEvent
136
             */
137
            $new_data['action'] = 'answer_pickup_create_cdr';
138
            $AgiData            = base64_encode(json_encode($new_data));
139
            $am = Util::getAstManager('off');
140
            $am->UserEvent('CdrConnector', ['AgiData' => $AgiData]);
141
        }
142
    }
143
144
    /**
145
     * Заполнение информации об отвеченном вызове.
146
     * @param $worker
147
     * @param $data
148
     * @param $row
149
     * @return int
150
     */
151
    private static function fillAnsweredCdr($worker, $data, $row): int
152
    {
153
154
        if ($row->dialstatus === 'ORIGINATE') {
155
            if ($row->src_chan !== $data['agi_channel']) {
156
                // Ищем совпадающий канал
157
                return self::NEED_CONTINUE;
158
            }
159
            // Найдем все прочие CDR по данному originate и отметим как завершенные.
160
            $filter      = [
161
                'linkedid=:linkedid: AND endtime <> "" AND src_chan <> :src_chan:',
162
                'bind' => [
163
                    'linkedid' => $row->linkedid,
164
                    'src_chan' => $data['agi_channel'],
165
                ],
166
            ];
167
            $m_orgn_data = CallDetailRecordsTmp::find($filter);
168
            /** @var CallDetailRecordsTmp $orgn_row */
169
            foreach ($m_orgn_data as $orgn_row) {
170
                if (empty($orgn_row->endtime)) {
171
                    $orgn_row->writeAttribute('endtime', $data['answer']);
172
                }
173
                $orgn_row->writeAttribute('dst_chan', '');
174
                $orgn_row->writeAttribute('UNIQUEID', $data['id'] . '_' . $orgn_row->src_chan);
175
                $orgn_row->update();
176
            }
177
178
            $row->writeAttribute('dst_chan', '');
179
            $row->writeAttribute('dialstatus', '');
180
            $row->writeAttribute('UNIQUEID', $data['id']);
181
            $row->save();
182
            return self::NEED_BREAK;
183
        }
184
185
        $row->writeAttribute('answer', $data['answer']);
186
        $recFile = $data['recordingfile']??'';
187
        if(!empty($recFile)){
188
            $worker->mixMonitorChannels[$data['agi_channel']] = $recFile;
189
            $row->writeAttribute('recordingfile', $recFile);
190
        }
191
        $res = $row->save();
192
        if ( !$res) {
193
            Util::sysLogMsg('Action_dial_answer', implode(' ', $row->getMessages()), LOG_DEBUG);
194
        }
195
        return self::NORM_EXIT;
196
    }
197
}