defmodule DaProductApp.TerminalManagement.TmsTerminal do use Ecto.Schema import Ecto.Changeset # Import event dispatcher for automatic rule application alias DaProductApp.TerminalManagement.TerminalEventDispatcher @derive {Jason.Encoder, only: [ :id, :serial_number, :oid, :status, :model, :vendor, :area, :group, :imei, :imei2, :cpuid, :mac, :app_version, :data_version, :system_version, :secure_firmware, :boot_version, :pubkey, :appkey, :locked, :hardware_version, :driver_version, :pro_version, :module_version, :wifi_version, :remark, :otp_id, :netmac, :heart, :inserted_at, :updated_at, :merchant_id, :location_code, :deployment_type, :tier, :parameter_config_version, :emv_config_version, :keys_config_version, :kek_kcv, :slot_number, :last_keys_update ]} @primary_key {:id, :id, autogenerate: true} @foreign_key_type :id schema "tms_terminals" do field :serial_number, :string field :oid, :string field :status, :string field :model, :string field :vendor, :string field :area, :string field :group, :string field :imei, :string field :imei2, :string field :cpuid, :string field :mac, :string field :app_version, :string field :data_version, :string field :system_version, :string field :secure_firmware, :string field :factory_time, :utc_datetime field :boot_version, :string field :pubkey, :string field :appkey, :string field :locked, :string field :hardware_version, :string field :driver_version, :string field :pro_version, :string field :module_version, :string field :wifi_version, :string field :remark, :string field :otp_id, :string field :netmac, :string field :heart, :integer # Version fields for auto-push field :parameter_config_version, :string field :emv_config_version, :string field :keys_config_version, :string # Keys configuration fields field :kek_kcv, :string field :slot_number, :integer field :last_keys_update, :utc_datetime # Additional fields for group rules field :merchant_id, :string field :location_code, :string field :deployment_type, :string field :tier, :string # Virtual field for event tracking (not persisted to database) field :__event_data__, :map, virtual: true has_many :status_logs, DaProductApp.TerminalManagement.TmsTerminalStatusLog, foreign_key: :terminal_id has_many :group_memberships, DaProductApp.TerminalManagement.TerminalGroupMembership, foreign_key: :terminal_id timestamps() end def changeset(terminal, attrs) do terminal |> cast(attrs, [ :serial_number, :oid, :status, :model, :vendor, :area, :group, :imei, :imei2, :cpuid, :mac, :app_version, :data_version, :system_version, :secure_firmware, :factory_time, :boot_version, :pubkey, :appkey, :locked, :hardware_version, :driver_version, :pro_version, :module_version, :wifi_version, :remark, :otp_id, :netmac, :heart, :merchant_id, :location_code, :deployment_type, :tier, :parameter_config_version, :emv_config_version, :keys_config_version, :kek_kcv, :slot_number, :last_keys_update ]) |> validate_required([:serial_number]) |> unique_constraint(:serial_number) |> maybe_trigger_events() end # Event-driven rule application defp maybe_trigger_events(changeset) do if changeset.valid? do # Add a function to track changes for event dispatching changeset |> put_change(:__event_data__, extract_event_data(changeset)) else changeset end end defp extract_event_data(changeset) do %{ is_new: is_nil(changeset.data.id), changes: changeset.changes, old_data: changeset.data } end end