7 * @link http://www.open-emr.org
8 * @author Matthew Vita <matthewvita48@gmail.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @author Sherwin Gaddis <sherwingaddis@gmail.com>
11 * @author Jerry Padgett <sjpadgett@gmail.com>
12 * @copyright Copyright (c) 2018 Matthew Vita <matthewvita48@gmail.com>
13 * @copyright Copyright (c) 2018 Brady Miller <brady.g.miller@gmail.com>
14 * @copyright Copyright (c) 2020 Jerry Padgett <sjpadgett@gmail.com>
15 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
18 namespace OpenEMR\Services
;
20 use OpenEMR\Common\Uuid\UuidRegistry
;
21 use OpenEMR\Validators\FacilityValidator
;
22 use OpenEMR\Validators\ProcessingResult
;
23 use OpenEMR\Events\Facility\FacilityCreatedEvent
;
24 use OpenEMR\Events\Facility\FacilityUpdatedEvent
;
25 use Particle\Validator\Validator
;
27 class FacilityService
extends BaseService
29 private $facilityValidator;
30 private $uuidRegistry;
31 private const FACILITY_TABLE
= "facility";
34 * Default constructor.
36 public function __construct()
38 parent
::__construct(self
::FACILITY_TABLE
);
39 $this->uuidRegistry
= new UuidRegistry(['table_name' => self
::FACILITY_TABLE
]);
40 $this->uuidRegistry
->createMissingUuids();
41 $this->facilityValidator
= new FacilityValidator();
44 public function validate($facility)
46 $validator = new Validator();
48 $validator->required('name')->lengthBetween(2, 255);
49 $validator->required('phone')->lengthBetween(3, 30);
50 $validator->required('city')->lengthBetween(2, 255);
51 $validator->required('state')->lengthBetween(2, 50);
52 $validator->required('street')->lengthBetween(2, 255);
53 $validator->required('postal_code')->lengthBetween(2, 11);
54 $validator->required('email')->email();
55 $validator->required('fax')->lengthBetween(3, 30);
56 $validator->optional('country_code')->lengthBetween(2, 30);
57 $validator->optional('federal_ein')->lengthBetween(2, 15);
58 $validator->optional('website')->url();
59 $validator->optional('color')->lengthBetween(4, 7);
60 $validator->optional('service_location')->numeric();
61 $validator->optional('billing_location')->numeric();
62 $validator->optional('accepts_assignment')->numeric();
63 $validator->optional('pos_code')->numeric();
64 $validator->optional('domain_identifier')->lengthBetween(2, 60);
65 $validator->optional('attn')->lengthBetween(2, 65);
66 $validator->optional('tax_id_type')->lengthBetween(2, 31);
67 $validator->optional('primary_business_entity')->numeric();
68 $validator->optional('facility_npi')->lengthBetween(2, 15);
69 $validator->optional('facility_code')->lengthBetween(2, 31);
70 $validator->optional('facility_taxonomy')->lengthBetween(2, 15);
71 $validator->optional('iban')->lengthBetween(2, 34);
73 return $validator->validate($facility);
76 public function getAllFacility()
78 return $this->get(array("order" => "ORDER BY FAC.name ASC"));
81 public function getPrimaryBusinessEntity($options = null)
83 if (!empty($options) && !empty($options["useLegacyImplementation"])) {
84 return $this->getPrimaryBusinessEntityLegacy();
88 "where" => "WHERE FAC.primary_business_entity = 1",
93 if (!empty($options) && !empty($options["excludedId"])) {
94 $args["where"] .= " AND FAC.id != ?";
95 $args["data"] = $options["excludedId"];
96 return $this->get($args);
99 return $this->get($args);
102 public function getAllServiceLocations($options = null)
106 "order" => "ORDER BY FAC.name ASC"
109 if (!empty($options) && !empty($options["orderField"])) {
110 $args["order"] = "ORDER BY FAC." . escape_sql_column_name($options["orderField"], array("facility")) . " ASC";
113 $args["where"] = "WHERE FAC.service_location = 1";
115 return $this->get($args);
118 public function getPrimaryBillingLocation()
120 return $this->get(array(
121 "order" => "ORDER BY FAC.billing_location DESC, FAC.id DESC",
126 public function getAllBillingLocations()
128 return $this->get(array(
129 "where" => "WHERE FAC.billing_location = 1",
130 "order" => "ORDER BY FAC.id ASC"
134 public function getById($id)
136 return $this->get(array(
137 "where" => "WHERE FAC.id = ?",
138 "data" => array($id),
143 public function getFacilityForUser($userId)
145 return $this->get(array(
146 "where" => "WHERE USER.id = ?",
147 "data" => array($userId),
148 "join" => "JOIN users USER ON FAC.id = USER.facility_id",
153 public function getFacilityForUserFormatted($userId)
155 $facility = $this->getFacilityForUser($userId);
157 if (!empty($facility)) {
159 $formatted .= $facility["name"];
161 $formatted .= $facility["street"];
163 $formatted .= $facility["city"];
165 $formatted .= $facility["state"];
167 $formatted .= $facility["postal_code"];
169 return array("facility_address" => $formatted);
172 return array("facility_address" => "");
175 public function getFacilityForEncounter($encounterId)
177 return $this->get(array(
178 "where" => "WHERE ENC.encounter = ?",
179 "data" => array($encounterId),
180 "join" => "JOIN form_encounter ENC ON FAC.id = ENC.facility_id",
185 public function updateFacility($data)
187 $dataBeforeUpdate = $this->getById($data['id']);
188 $query = $this->buildUpdateColumns($data);
189 $sql = " UPDATE facility SET ";
190 $sql .= $query['set'];
191 $sql .= " WHERE id = ?";
192 array_push($query['bind'], $data['id']);
193 $result = sqlStatement(
198 $facilityUpdatedEvent = new FacilityUpdatedEvent($dataBeforeUpdate, $data);
199 $GLOBALS["kernel"]->getEventDispatcher()->dispatch(FacilityUpdatedEvent
::EVENT_HANDLE
, $facilityUpdatedEvent, 10);
204 public function insertFacility($data)
206 $query = $this->buildInsertColumns($data);
207 $sql = " INSERT INTO facility SET ";
208 $sql .= $query['set'];
209 $facilityId = sqlInsert(
214 $facilityCreatedEvent = new FacilityCreatedEvent(array_merge($data, ['id' => $facilityId]));
215 $GLOBALS["kernel"]->getEventDispatcher()->dispatch(FacilityCreatedEvent
::EVENT_HANDLE
, $facilityCreatedEvent, 10);
220 public function updateUsersFacility($facility_name, $facility_id)
222 $sql = " UPDATE users SET";
223 $sql .= " facility=?";
224 $sql .= " WHERE facility_id=?";
226 return sqlStatement($sql, array($facility_name, $facility_id));
230 * Shared getter for the various specific facility getters.
232 * @param $map - Query information.
233 * @return array of associative arrays | one associative array.
235 private function get($map)
237 $sql = " SELECT FAC.id,";
238 $sql .= " FAC.uuid,";
239 $sql .= " FAC.name,";
240 $sql .= " FAC.phone,";
242 $sql .= " FAC.street,";
243 $sql .= " FAC.city,";
244 $sql .= " FAC.state,";
245 $sql .= " FAC.postal_code,";
246 $sql .= " FAC.country_code,";
247 $sql .= " FAC.federal_ein,";
248 $sql .= " FAC.website,";
249 $sql .= " FAC.email,";
250 $sql .= " FAC.service_location,";
251 $sql .= " FAC.billing_location,";
252 $sql .= " FAC.accepts_assignment,";
253 $sql .= " FAC.pos_code,";
254 $sql .= " FAC.x12_sender_id,";
255 $sql .= " FAC.attn,";
256 $sql .= " FAC.domain_identifier,";
257 $sql .= " FAC.facility_npi,";
258 $sql .= " FAC.facility_taxonomy,";
259 $sql .= " FAC.tax_id_type,";
260 $sql .= " FAC.color,";
261 $sql .= " FAC.primary_business_entity,";
262 $sql .= " FAC.facility_code,";
263 $sql .= " FAC.extra_validation,";
264 $sql .= " FAC.mail_street,";
265 $sql .= " FAC.mail_street2,";
266 $sql .= " FAC.mail_city,";
267 $sql .= " FAC.mail_state,";
268 $sql .= " FAC.mail_zip,";
270 $sql .= " FAC.iban,";
272 $sql .= " FROM facility FAC";
274 return self
::selectHelper($sql, $map);
277 private function getPrimaryBusinessEntityLegacy()
279 return $this->get(array(
280 "order" => "ORDER BY FAC.billing_location DESC, FAC.accepts_assignment DESC, FAC.id ASC",
286 * Returns a list of facilities matching optional search criteria.
287 * Search criteria is conveyed by array where key = field/column name, value = field value.
288 * If no search criteria is provided, all records are returned.
290 * @param $search search array parameters
291 * @param $isAndCondition specifies if AND condition is used for multiple criteria. Defaults to true.
292 * @return ProcessingResult which contains validation messages, internal error messages, and the data
295 public function getAll($search = array(), $isAndCondition = true)
297 $processingResult = new ProcessingResult();
299 // Validating and Converting _id to UUID byte
300 if (isset($search['uuid'])) {
301 $isValid = $this->facilityValidator
->validateId(
303 self
::FACILITY_TABLE
,
307 if ($isValid != true) {
310 $search['uuid'] = UuidRegistry
::uuidToBytes($search['uuid']);
312 $additionalSql = array();
313 if (!empty($search)) {
314 $additionalSql['where'] = ' WHERE ';
315 $additionalSql["data"] = array();
316 $whereClauses = array();
317 foreach ($search as $fieldName => $fieldValue) {
319 array_push($whereClauses, $fieldName . ' = ?');
320 array_push($additionalSql["data"], $fieldValue);
322 $sqlCondition = ($isAndCondition == true) ?
'AND' : 'OR';
323 $additionalSql['where'] .= implode(' ' . $sqlCondition . ' ', $whereClauses);
325 $statementResults = $this->get($additionalSql);
326 if ($statementResults) {
327 foreach ($statementResults as $row) {
328 $row['uuid'] = UuidRegistry
::uuidToString($row['uuid']);
329 $processingResult->addData($row);
333 return $processingResult;
337 * Returns a single facility record by facility uuid.
338 * @param $uuid - The facility uuid identifier in string format.
339 * @return ProcessingResult which contains validation messages, internal error messages, and the data
342 public function getOne($uuid)
344 $processingResult = new ProcessingResult();
345 $isValid = $this->facilityValidator
->validateId('uuid', self
::FACILITY_TABLE
, $uuid, true);
346 if ($isValid !== true) {
349 $uuidBytes = UuidRegistry
::uuidToBytes($uuid);
350 $sqlResult = $this->get(array(
351 "where" => "WHERE FAC.uuid = ?",
352 "data" => array($uuidBytes),
357 $sqlResult['uuid'] = UuidRegistry
::uuidToString($sqlResult['uuid']);
358 $processingResult->addData($sqlResult);
360 $processingResult->addInternalError("error processing SQL Insert");
363 return $processingResult;
367 * Inserts a new facility record.
369 * @param $data The facility fields (array) to insert.
370 * @return ProcessingResult which contains validation messages, internal error messages, and the data
373 public function insert($data)
375 $processingResult = $this->facilityValidator
->validate(
377 FacilityValidator
::DATABASE_INSERT_CONTEXT
380 if (!$processingResult->isValid()) {
381 return $processingResult;
384 $data['uuid'] = (new UuidRegistry(['table_name' => self
::FACILITY_TABLE
]))->createUuid();
386 $query = $this->buildInsertColumns($data);
387 $sql = " INSERT INTO " . self
::FACILITY_TABLE
. " SET ";
388 $sql .= $query['set'];
390 $results = sqlInsert(
396 $processingResult->addData(array(
398 'uuid' => UuidRegistry
::uuidToString($data['uuid'])
401 $processingResult->addInternalError("error processing SQL Insert");
404 return $processingResult;
408 * Updates an existing facility record.
410 * @param $uuid - The facility uuid identifier in string format used for update.
411 * @param $data - The updated facility data fields
412 * @return ProcessingResult which contains validation messages, internal error messages, and the data
415 public function update($uuid, $data)
418 $processingResult = new ProcessingResult();
419 $processingResult->setValidationMessages("Invalid Data");
420 return $processingResult;
422 $data["uuid"] = $uuid;
423 $processingResult = $this->facilityValidator
->validate(
425 FacilityValidator
::DATABASE_UPDATE_CONTEXT
427 if (!$processingResult->isValid()) {
428 return $processingResult;
431 $query = $this->buildUpdateColumns($data);
432 $sql = " UPDATE " . self
::FACILITY_TABLE
. " SET ";
433 $sql .= $query['set'];
434 $sql .= " WHERE `uuid` = ?";
436 $uuidBinary = UuidRegistry
::uuidToBytes($uuid);
437 array_push($query['bind'], $uuidBinary);
438 $sqlResult = sqlStatement($sql, $query['bind']);
441 $processingResult->addErrorMessage("error processing SQL Update");
443 $processingResult = $this->getOne($uuid);
445 return $processingResult;