/**
  * Create movement
  *
  * @param string       $code        HL7 event code
  * @param CSejour      $sejour      Admit
  * @param CAffectation $affectation Affectation
  *
  * @return CMovement|mixed
  */
 function createMovement($code, CSejour $sejour, CAffectation $affectation = null)
 {
     $insert = in_array($code, CHL7v2SegmentZBE::$actions["INSERT"]);
     $update = in_array($code, CHL7v2SegmentZBE::$actions["UPDATE"]);
     $cancel = in_array($code, CHL7v2SegmentZBE::$actions["CANCEL"]);
     $movement = new CMovement();
     // Initialise le mouvement
     $movement->sejour_id = $sejour->_id;
     $receiver = $sejour->_receiver;
     $configs = $receiver->_configs;
     $affectation_id = null;
     if ($affectation) {
         $current_log = $affectation->_ref_current_log;
         $first_affectation = $sejour->loadRefFirstAffectation();
         /** @var CService $service */
         $service = $affectation->loadRefService();
         // Si le service est d'UHCD, de radiologie, d'urgence ou
         // Dans le cas où il s'agit de la première affectation du séjour et qu'on est en type "création" on ne recherche pas
         // un mouvement avec l'affectation, mais on va prendre le mouvement d'admission
         if ($service->uhcd || $service->radiologie || $service->urgence || $current_log && $current_log->type == "create" && $first_affectation && $first_affectation->_id == $affectation->_id) {
             switch ($configs["send_first_affectation"]) {
                 case 'Z99':
                     $affectation_id = $affectation->_id;
                     $affectation = null;
                     break;
                 default:
                     $movement->affectation_id = $affectation->_id;
             }
         } else {
             $movement->affectation_id = $affectation->_id;
         }
     }
     if ($insert) {
         // Dans le cas d'un insert le type correspond nécessairement au type actuel du séjour
         $movement->movement_type = $sejour->getMovementType($code);
         $movement->original_trigger_code = $code;
         $movement->start_of_movement = $this->getStartOfMovement($code, $sejour, $affectation);
         $movement->loadMatchingObject();
         $movement->store();
         return $sejour->_ref_hl7_movement = $movement;
     } elseif ($update) {
         // Dans le cas d'un update le type correspond à celui du trigger
         $movement_type = null;
         // Mise à jour entrée réelle
         if ($sejour->fieldModified("entree_reelle")) {
             $movement_type = "ADMI";
         }
         // Mise à jour sortie réelle
         if ($sejour->fieldModified("sortie_reelle")) {
             $movement_type = "SORT";
         }
         $movement->movement_type = $movement_type;
         // On ne recherche pas parmi les mouvements annulés
         $movement->cancel = 0;
     }
     $order = "affectation_id DESC";
     $movements = $movement->loadMatchingList($order);
     if (!empty($movements)) {
         $movement = reset($movements);
     }
     if ($update) {
         if ($movement->original_trigger_code == "A02") {
             if (!$affectation) {
                 $affectation = new CAffectation();
             }
             $affectation->load($movement->affectation_id);
         }
         $movement->start_of_movement = $this->getStartOfMovement($movement->original_trigger_code, $sejour, $affectation, $movement);
     }
     // on annule un mouvement sauf dans le cas d'une annulation de mutation et que
     if ($cancel && !($code == "A12" && $movement->original_trigger_code != "A02")) {
         $movement->cancel = 1;
     }
     if ($affectation_id) {
         $movement->affectation_id = $affectation_id;
     }
     $movement->store();
     return $sejour->_ref_hl7_movement = $movement;
 }
 /**
  * Handle event A05 - pre-admit a patient
  *
  * @param CHL7Acknowledgment $ack      Acknowledgment
  * @param CSejour            $newVenue Admit
  * @param array              $data     Datas
  *
  * @return string
  */
 function handleA05(CHL7Acknowledgment $ack, CSejour $newVenue, $data)
 {
     // Mapping venue - création possible
     $_modif_sejour = false;
     $exchange_hl7v2 = $this->_ref_exchange_hl7v2;
     $sender = $this->_ref_sender;
     $venueRI = CValue::read($data['admitIdentifiers'], "RI");
     //$venueRISender = CValue::read($data['admitIdentifiers'], "RI_Sender");
     $venueNPA = CValue::read($data['admitIdentifiers'], "NPA");
     $venueVN = CValue::read($data['admitIdentifiers'], "VN");
     $venueAN = $this->getVenueAN($sender, $data);
     $NDA = new CIdSante400();
     $sender_purge_idex_movements = $sender->_configs["purge_idex_movements"];
     if ($venueAN) {
         $NDA = CIdSante400::getMatch("CSejour", $sender->_tag_sejour, $venueAN);
     }
     // NDA non connu (non fourni ou non retrouvé)
     if (!$NDA->_id) {
         // Aucun NDA fourni / Association du NDA
         $code_NDA = !$venueAN ? "I225" : "I222";
         $found = false;
         // NPA fourni
         if (!$found && $venueNPA) {
             $manage_npa = CMbArray::get($sender->_configs, "manage_npa");
             if ($manage_npa) {
                 $NPA = CIdSante400::getMatch("CSejour", $sender->_tag_sejour, $venueNPA);
                 if ($NPA->_id) {
                     $found = true;
                 }
                 $newVenue->load($NPA->object_id);
                 // Mapping de la venue
                 $this->mappingVenue($data, $newVenue);
                 // Notifier les autres destinataires autre que le sender
                 $newVenue->_eai_sender_guid = $sender->_guid;
                 // On ne check pas la cohérence des dates des consults/intervs
                 $newVenue->_skip_date_consistencies = true;
                 if ($msgVenue = $newVenue->store()) {
                     if ($newVenue->_collisions) {
                         return $exchange_hl7v2->setAckAR($ack, "E213", $msgVenue, reset($newVenue->_collisions));
                     }
                     return $exchange_hl7v2->setAckAR($ack, "E201", $msgVenue, $newVenue);
                 }
             } else {
                 /* @todo Gérer ce cas */
                 $venueRI = $venueNPA;
             }
         }
         // VN fourni
         if (!$found && $venueVN && !$sender_purge_idex_movements) {
             // Le champ PV1.2 conditionne le remplissage et l'interprétation de PV1.19
             $this->getSejourByVisitNumber($newVenue, $data);
             if ($newVenue->_id) {
                 $found = true;
                 // Mapping du séjour
                 $this->mappingVenue($data, $newVenue);
                 // Notifier les autres destinataires autre que le sender
                 $newVenue->_eai_sender_guid = $sender->_guid;
                 // Pas de génération de NDA
                 $newVenue->_generate_NDA = false;
                 // On ne check pas la cohérence des dates des consults/intervs
                 $newVenue->_skip_date_consistencies = true;
                 if ($msgVenue = $newVenue->store()) {
                     if ($newVenue->_collisions) {
                         return $exchange_hl7v2->setAckAR($ack, "E213", $msgVenue, reset($newVenue->_collisions));
                     }
                     return $exchange_hl7v2->setAckAR($ack, "E201", $msgVenue, $newVenue);
                 }
                 $code_NDA = "A222";
                 $_modif_sejour = true;
             }
         }
         // RI fourni
         if (!$found && $venueRI) {
             // Recherche du séjour par son RI
             if ($newVenue->load($venueRI)) {
                 // Mapping du séjour
                 $this->mappingVenue($data, $newVenue);
                 // Le séjour retrouvé est-il différent que celui du message ?
                 /* @todo voir comment faire (même patient, même praticien, même date ?) */
                 // Notifier les autres destinataires autre que le sender
                 $newVenue->_eai_sender_guid = $sender->_guid;
                 // Pas de génération de NDA
                 $newVenue->_generate_NDA = false;
                 // On ne check pas la cohérence des dates des consults/intervs
                 $newVenue->_skip_date_consistencies = true;
                 if ($msgVenue = $newVenue->store()) {
                     if ($newVenue->_collisions) {
                         return $exchange_hl7v2->setAckAR($ack, "E213", $msgVenue, reset($newVenue->_collisions));
                     }
                     return $exchange_hl7v2->setAckAR($ack, "E201", $msgVenue, $newVenue);
                 }
                 $code_NDA = "I221";
                 $_modif_sejour = true;
             } else {
                 $code_NDA = "I220";
             }
         }
         if (!$newVenue->_id) {
             // Mapping du séjour
             $this->mappingVenue($data, $newVenue);
             // Séjour retrouvé ?
             if (CAppUI::conf("hl7 strictSejourMatch")) {
                 // Recherche d'un num dossier déjà existant pour cette venue
                 if ($newVenue->loadMatchingSejour(null, true, false)) {
                     $code_NDA = "A221";
                     $_modif_sejour = true;
                 }
             } else {
                 // Valuer "entree" et "sortie"
                 $newVenue->updatePlainFields();
                 $collision = $newVenue->getCollisions();
                 if (count($collision) == 1) {
                     $newVenue = reset($collision);
                     $code_NDA = "A222";
                     $_modif_sejour = true;
                 }
             }
             // Mapping du séjour
             $newVenue = $this->mappingVenue($data, $newVenue);
             // Notifier les autres destinataires autre que le sender
             $newVenue->_eai_sender_guid = $sender->_guid;
             // Pas de génération de NDA
             $newVenue->_generate_NDA = false;
             // On ne check pas la cohérence des dates des consults/intervs
             $newVenue->_skip_date_consistencies = true;
             if ($msgVenue = $newVenue->store()) {
                 if ($newVenue->_collisions) {
                     return $exchange_hl7v2->setAckAR($ack, "E213", $msgVenue, reset($newVenue->_collisions));
                 }
                 return $exchange_hl7v2->setAckAR($ack, "E201", $msgVenue, $newVenue);
             }
         }
         if ($msgNDA = CEAISejour::storeNDA($NDA, $newVenue, $sender)) {
             return $exchange_hl7v2->setAckAR($ack, "E202", $msgNDA, $newVenue);
         }
         if ($msgNRA = $this->getAlternateVisitID($data["PV1"], $newVenue)) {
             return $exchange_hl7v2->setAckAR($ack, "E214", $msgNRA, $newVenue);
         }
         // Création du VN, voir de l'objet
         if ($msgVN = $this->createObjectByVisitNumber($newVenue, $data)) {
             return $exchange_hl7v2->setAckAR($ack, "E210", $msgVN, $newVenue);
         }
         $codes = array($_modif_sejour ? "I202" : "I201", $code_NDA);
         $comment = CEAISejour::getComment($newVenue);
         $comment .= CEAISejour::getComment($NDA);
     } else {
         $newVenue->load($NDA->object_id);
         // Mapping de la venue
         $this->mappingVenue($data, $newVenue);
         // RI non fourni
         if (!$venueRI) {
             $code_NDA = "I223";
         } else {
             $tmpVenue = new CSejour();
             // RI connu
             if ($tmpVenue->load($venueRI)) {
                 if ($tmpVenue->_id != $NDA->object_id) {
                     $comment = "L'id source fait référence au séjour : {$NDA->object_id} et l'id cible au séjour : {$tmpVenue->_id}.";
                     return $exchange_hl7v2->setAckAR($ack, "E230", $comment, $newVenue);
                 }
                 $code_NDA = "I224";
             } else {
                 $code_NDA = "A220";
             }
         }
         // Notifier les autres destinataires autre que le sender
         $newVenue->_eai_sender_guid = $sender->_guid;
         // On ne check pas la cohérence des dates des consults/intervs
         $newVenue->_skip_date_consistencies = true;
         if ($msgVenue = $newVenue->store()) {
             if ($newVenue->_collisions) {
                 return $exchange_hl7v2->setAckAR($ack, "E213", $msgVenue, reset($newVenue->_collisions));
             }
             return $exchange_hl7v2->setAckAR($ack, "E201", $msgVenue, $newVenue);
         }
         // Création du VN, voir de l'objet
         if ($msgVN = $this->createObjectByVisitNumber($newVenue, $data)) {
             return $exchange_hl7v2->setAckAR($ack, "E210", $msgVN, $newVenue);
         }
         $codes = array("I202", $code_NDA);
         $comment = CEAISejour::getComment($newVenue);
     }
     // Mapping du mouvement
     if ($sender_purge_idex_movements) {
         // On recherche un mouvement de l'event (A05/A01/A04)
         $movement = new CMovement();
         $movement->sejour_id = $newVenue->_id;
         $movement->original_trigger_code = $this->_ref_exchange_hl7v2->code;
         $movement->cancel = 0;
         $movement->loadMatchingObject();
         // Si on a un mouvement alors on annule tous les autres
         if ($movement->_id) {
             foreach ($newVenue->loadRefsMovements() as $_movement) {
                 // On passe en trash l'idex associé
                 $_movement->loadLastId400();
                 $last_id400 = $_movement->_ref_last_id400;
                 if ($last_id400->_id) {
                     $last_id400->tag = "trash_" . $last_id400->tag;
                     $last_id400->last_update = CMbDT::dateTime();
                     $last_id400->_eai_sender_guid = $sender->_guid;
                     $last_id400->store();
                 }
                 // On annule le mouvement
                 $_movement->cancel = 1;
                 $_movement->_eai_sender_guid = $sender->_guid;
                 $_movement->store();
             }
         }
     }
     $return_movement = $this->mapAndStoreMovement($ack, $newVenue, $data);
     if (is_string($return_movement)) {
         return $return_movement;
     }
     $movement = $return_movement;
     // Mapping de l'affectation
     $return_affectation = $this->mapAndStoreAffectation($newVenue, $data, $return_movement);
     if (is_string($return_affectation)) {
         return $exchange_hl7v2->setAckAR($ack, "E208", $return_affectation, $newVenue);
     }
     $affectation = $return_affectation;
     // Affectation de l'affectation au mouvement
     if ($movement && $affectation && $affectation->_id) {
         $movement->affectation_id = $affectation->_id;
         $movement->_eai_sender_guid = $sender->_guid;
         $movement->store();
     }
     // Dans le cas d'une grossesse
     if ($return_grossesse = $this->storeGrossesse($newVenue)) {
         return $exchange_hl7v2->setAckAR($ack, "E211", $return_grossesse, $newVenue);
     }
     // Dans le cas d'une naissance
     if ($return_naissance = $this->mapAndStoreNaissance($newVenue, $data)) {
         return $exchange_hl7v2->setAckAR($ack, "E212", $return_naissance, $newVenue);
     }
     return $exchange_hl7v2->setAckAA($ack, $codes, $comment, $newVenue);
 }