zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

domain.test.exs (75067B)


      1 # Zenflows is designed to implement the Valueflows vocabulary,
      2 # written and maintained by srfsh <info@dyne.org>.
      3 # Copyright (C) 2021-2023 Dyne.org foundation <foundation@dyne.org>.
      4 #
      5 # This program is free software: you can redistribute it and/or modify
      6 # it under the terms of the GNU Affero General Public License as published by
      7 # the Free Software Foundation, either version 3 of the License, or
      8 # (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU Affero General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU Affero General Public License
     16 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
     17 
     18 defmodule ZenflowsTest.VF.EconomicEvent.Domain do
     19 use ZenflowsTest.Help.EctoCase, async: true
     20 
     21 import Ecto.Query
     22 
     23 alias Ecto.Changeset
     24 alias Zenflows.DB.Repo
     25 alias Zenflows.VF.{
     26 	EconomicEvent,
     27 	EconomicEvent.Domain,
     28 	EconomicResource,
     29 	Process,
     30 }
     31 
     32 setup ctx do
     33 	if ctx[:no_resource] do
     34 		:ok
     35 	else
     36 		agent = Factory.insert!(:agent)
     37 		params = %{
     38 			action_id: "raise",
     39 			provider_id: agent.id,
     40 			receiver_id: agent.id,
     41 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
     42 			resource_quantity: %{
     43 				has_unit_id: Factory.insert!(:unit).id,
     44 				has_numerical_value: Factory.decimal(),
     45 			},
     46 			has_end: Factory.now(),
     47 		}
     48 		assert %EconomicEvent{resource_inventoried_as: res} =
     49 			Domain.create!(params, %{name: Factory.str("name")})
     50 			|> Domain.preload(:resource_inventoried_as)
     51 
     52 		if ctx[:want_contained] || ctx[:want_container] do
     53 			agent = Factory.insert!(:agent)
     54 			params = %{
     55 				action_id: "raise",
     56 				provider_id: agent.id,
     57 				receiver_id: agent.id,
     58 				resource_conforms_to_id: Factory.insert!(:resource_specification).id,
     59 				resource_quantity: %{
     60 					has_unit_id: Factory.insert!(:unit).id,
     61 					has_numerical_value: Factory.decimal(),
     62 				},
     63 				has_end: Factory.now(),
     64 			}
     65 			assert %EconomicEvent{resource_inventoried_as: tmp_res} =
     66 				Domain.create!(params, %{name: Factory.str("name")})
     67 				|> Domain.preload(:resource_inventoried_as)
     68 
     69 			# TODO: use combine-separate when implemented instead
     70 			if ctx[:want_contained] do
     71 				Changeset.change(res, contained_in_id: tmp_res.id) |> Repo.update!()
     72 			end
     73 
     74 			if ctx[:want_container] do
     75 				Changeset.change(tmp_res, contained_in_id: res.id) |> Repo.update!()
     76 			end
     77 		end
     78 
     79 		%{res: res}
     80 	end
     81 end
     82 
     83 #@tag :skip
     84 #test "one/1 returns a EconomicEvent", %{inserted: new} do
     85 #	assert {:ok, %EconomicEvent{}} = Domain.one(new.id)
     86 #end
     87 
     88 describe "`create/2` with raise:" do
     89 	setup ctx do
     90 		if ctx[:no_resource] do
     91 			:ok
     92 		else
     93 			res = ctx.res
     94 			%{params: %{
     95 				action_id: "raise",
     96 				provider_id: res.primary_accountable_id,
     97 				receiver_id: res.primary_accountable_id,
     98 				resource_inventoried_as_id: res.id,
     99 				resource_quantity: %{
    100 					has_unit_id: res.accounting_quantity_has_unit_id,
    101 					has_numerical_value: Factory.decimal(),
    102 				},
    103 				has_point_in_time: Factory.now(),
    104 			}}
    105 		end
    106 	end
    107 
    108 	@tag :no_resource
    109 	test "pass with `:resource_conforms_to`" do
    110 		agent = Factory.insert!(:agent)
    111 		evt_params = %{
    112 			action_id: "raise",
    113 			provider_id: agent.id,
    114 			receiver_id: agent.id,
    115 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
    116 			resource_quantity: %{
    117 				has_unit_id: Factory.insert!(:unit).id,
    118 				has_numerical_value: Factory.decimal(),
    119 			},
    120 			has_end: Factory.now(),
    121 			to_location_id: Factory.insert!(:spatial_thing).id,
    122 		}
    123 		res_params = %{
    124 			name: Factory.str("name"),
    125 			note: Factory.str("note"),
    126 			#image: Factory.img(),
    127 			tracking_identifier: Factory.str("tracking identifier"),
    128 			lot_id: Factory.insert!(:product_batch).id,
    129 			okhv: Factory.str("okhv"),
    130 			repo: Factory.uri(),
    131 			version: Factory.str("version"),
    132 			licensor: Factory.str("licensor"),
    133 			license: Factory.str("license"),
    134 			metadata: %{Factory.str("key") => Factory.str("val")},
    135 		}
    136 		assert {:ok, %EconomicEvent{} = evt} =
    137 			Domain.create(evt_params, res_params)
    138 		evt = Domain.preload(evt, :resource_inventoried_as)
    139 		res = evt.resource_inventoried_as
    140 
    141 		assert res.name == res_params.name
    142 		assert res.note == res_params.note
    143 		#assert res.image == res_params.image
    144 		assert res.tracking_identifier == res_params.tracking_identifier
    145 		assert res.lot_id == res_params.lot_id
    146 		assert res.okhv == res_params.okhv
    147 		assert res.repo == res_params.repo
    148 		assert res.version == res_params.version
    149 		assert res.licensor == res_params.licensor
    150 		assert res.license == res_params.license
    151 		assert res.metadata == res_params.metadata
    152 
    153 		assert res.primary_accountable_id == evt_params.receiver_id
    154 		assert res.custodian_id == evt_params.receiver_id
    155 		assert Decimal.eq?(res.accounting_quantity_has_numerical_value, evt_params.resource_quantity.has_numerical_value)
    156 		assert res.accounting_quantity_has_unit_id == evt_params.resource_quantity.has_unit_id
    157 		assert Decimal.eq?(res.onhand_quantity_has_numerical_value, evt_params.resource_quantity.has_numerical_value)
    158 		assert res.onhand_quantity_has_unit_id == evt_params.resource_quantity.has_unit_id
    159 		assert res.current_location_id == evt_params.to_location_id
    160 	end
    161 
    162 	test "pass with `:resource_inventoried_as`", %{params: params} do
    163 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    164 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    165 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    166 
    167 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
    168 			Decimal.add(res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    169 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
    170 			Decimal.add(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    171 	end
    172 
    173 	test "fail when the agent doesn't have ownership over the resource", %{params: params} do
    174 		agent = Factory.insert!(:agent)
    175 		params =
    176 			params
    177 			|> Map.put(:provider_id, agent.id)
    178 			|> Map.put(:receiver_id, agent.id)
    179 		assert {:error, "you don't have ownership over this resource"} =
    180 			Domain.create(params)
    181 	end
    182 
    183 	test "fail when event's unit and resource's unit differ", %{params: params} do
    184 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
    185 		assert {:error, "the unit of resource quantity must match with the unit of this resource"} =
    186 			Domain.create(params)
    187 	end
    188 
    189 	@tag :want_contained
    190 	test "fail when the resource is a contained resource", %{params: params} do
    191 		assert {:error, "you can't raise into a contained resource"} = Domain.create(params)
    192 	end
    193 
    194 	@tag :want_container
    195 	test "fail when the resource is a container resource", %{params: params} do
    196 		assert {:error, "you can't raise into a container resource"} = Domain.create(params)
    197 	end
    198 end
    199 
    200 describe "`create/2` with produce:" do
    201 	setup ctx do
    202 		if ctx[:no_resource] do
    203 			:ok
    204 		else
    205 			res = ctx.res
    206 			%{params: %{
    207 				action_id: "produce",
    208 				output_of_id: Factory.insert!(:process).id,
    209 				provider_id: res.primary_accountable_id,
    210 				receiver_id: res.primary_accountable_id,
    211 				resource_inventoried_as_id: res.id,
    212 				resource_quantity: %{
    213 					has_unit_id: res.accounting_quantity_has_unit_id,
    214 					has_numerical_value: Factory.decimal(),
    215 				},
    216 				has_beginning: Factory.now(),
    217 			}}
    218 		end
    219 	end
    220 
    221 	@tag :no_resource
    222 	test "pass with `:resource_conforms_to`" do
    223 		agent = Factory.insert!(:agent)
    224 		evt_params = %{
    225 			action_id: "produce",
    226 			output_of_id: Factory.insert!(:process).id,
    227 			provider_id: agent.id,
    228 			receiver_id: agent.id,
    229 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
    230 			resource_quantity: %{
    231 				has_unit_id: Factory.insert!(:unit).id,
    232 				has_numerical_value: Factory.decimal(),
    233 			},
    234 			has_end: Factory.now(),
    235 			to_location_id: Factory.insert!(:spatial_thing).id,
    236 		}
    237 		res_params = %{
    238 			name: Factory.str("name"),
    239 			note: Factory.str("note"),
    240 			#image: Factory.img(),
    241 			tracking_identifier: Factory.str("tracking identifier"),
    242 			lot_id: Factory.insert!(:product_batch).id,
    243 			okhv: Factory.str("okhv"),
    244 			repo: Factory.uri(),
    245 			version: Factory.str("version"),
    246 			licensor: Factory.str("licensor"),
    247 			license: Factory.str("license"),
    248 			metadata: %{Factory.str("key") => Factory.str("val")},
    249 		}
    250 		assert {:ok, %EconomicEvent{} = evt} =
    251 			Domain.create(evt_params, res_params)
    252 		evt = Domain.preload(evt, :resource_inventoried_as)
    253 		res = evt.resource_inventoried_as
    254 
    255 		assert res.name == res_params.name
    256 		assert res.note == res_params.note
    257 		#assert res.image == res_params.image
    258 		assert res.tracking_identifier == res_params.tracking_identifier
    259 		assert res.lot_id == res_params.lot_id
    260 		assert res.okhv == res_params.okhv
    261 		assert res.repo == res_params.repo
    262 		assert res.version == res_params.version
    263 		assert res.licensor == res_params.licensor
    264 		assert res.license == res_params.license
    265 		assert res.metadata == res_params.metadata
    266 
    267 		assert res.primary_accountable_id == evt_params.receiver_id
    268 		assert res.custodian_id == evt_params.receiver_id
    269 		assert Decimal.eq?(res.accounting_quantity_has_numerical_value, evt_params.resource_quantity.has_numerical_value)
    270 		assert res.accounting_quantity_has_unit_id == evt_params.resource_quantity.has_unit_id
    271 		assert Decimal.eq?(res.onhand_quantity_has_numerical_value, evt_params.resource_quantity.has_numerical_value)
    272 		assert res.onhand_quantity_has_unit_id == evt_params.resource_quantity.has_unit_id
    273 		assert res.current_location_id == evt_params.to_location_id
    274 	end
    275 
    276 	test "pass with `:resource_inventoried_as`", %{params: params} do
    277 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    278 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    279 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    280 
    281 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
    282 			Decimal.add(res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    283 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
    284 			Decimal.add(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    285 	end
    286 
    287 	test "fail when the agent doesn't have ownership over the resource", %{params: params} do
    288 		agent = Factory.insert!(:agent)
    289 		params =
    290 			params
    291 			|> Map.put(:provider_id, agent.id)
    292 			|> Map.put(:receiver_id, agent.id)
    293 		assert {:error, "you don't have ownership over this resource"} =
    294 			Domain.create(params)
    295 	end
    296 
    297 	test "fail when event's unit and resource's unit differ", %{params: params} do
    298 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
    299 		assert {:error, "the unit of resource quantity must match with the unit of this resource"} =
    300 			Domain.create(params)
    301 	end
    302 
    303 	@tag :want_contained
    304 	test "fail when the resource is a contained resource", %{params: params} do
    305 		assert {:error, "you can't produce into a contained resource"} = Domain.create(params)
    306 	end
    307 
    308 	@tag :want_container
    309 	test "fail when the resource is a container resource", %{params: params} do
    310 		assert {:error, "you can't produce into a container resource"} = Domain.create(params)
    311 	end
    312 end
    313 
    314 describe "`create/2` with lower:" do
    315 	setup %{res: res} do
    316 		%{params: %{
    317 			action_id: "lower",
    318 			provider_id: res.primary_accountable_id,
    319 			receiver_id: res.primary_accountable_id,
    320 			resource_inventoried_as_id: res.id,
    321 			resource_quantity: %{
    322 				has_unit_id: res.accounting_quantity_has_unit_id,
    323 				has_numerical_value: Factory.decimal(),
    324 			},
    325 			has_end: Factory.now(),
    326 		}}
    327 	end
    328 
    329 	test "pass when all good", %{params: params} do
    330 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    331 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    332 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    333 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
    334 			Decimal.sub(res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    335 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
    336 			Decimal.sub(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    337 	end
    338 
    339 	test "fail when the agent doesn't have ownership over the resource", %{params: params} do
    340 		agent = Factory.insert!(:agent)
    341 		params =
    342 			params
    343 			|> Map.put(:provider_id, agent.id)
    344 			|> Map.put(:receiver_id, agent.id)
    345 		assert {:error, "you don't have ownership over this resource"} =
    346 			Domain.create(params)
    347 	end
    348 
    349 	test "fail when event's unit and resource's unit differ", %{params: params} do
    350 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
    351 		assert {:error, "the unit of resource quantity must match with the unit of this resource"} =
    352 			Domain.create(params)
    353 	end
    354 
    355 	@tag :want_contained
    356 	test "fail when the resource is a contained resource", %{params: params} do
    357 		assert {:error, "you can't lower a contained resource"} = Domain.create(params)
    358 	end
    359 
    360 	@tag :want_container
    361 	test "fail when the resource is a container resource", %{params: params} do
    362 		assert {:error, "you can't lower a container resource"} = Domain.create(params)
    363 	end
    364 end
    365 
    366 describe "`create/2` with consume:" do
    367 	setup %{res: res} do
    368 		%{params: %{
    369 			action_id: "consume",
    370 			input_of_id: Factory.insert!(:process).id,
    371 			provider_id: res.primary_accountable_id,
    372 			receiver_id: res.primary_accountable_id,
    373 			resource_inventoried_as_id: res.id,
    374 			resource_quantity: %{
    375 				has_unit_id: res.accounting_quantity_has_unit_id,
    376 				has_numerical_value: Factory.decimal(),
    377 			},
    378 			has_beginning: Factory.now(),
    379 			has_end: Factory.now(),
    380 		}}
    381 	end
    382 
    383 	test "pass when all good", %{params: params} do
    384 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    385 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    386 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    387 
    388 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
    389 			Decimal.sub(res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    390 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
    391 			Decimal.sub(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    392 	end
    393 
    394 	test "fail when the agent doesn't have ownership over the resource", %{params: params} do
    395 		agent = Factory.insert!(:agent)
    396 		params =
    397 			params
    398 			|> Map.put(:provider_id, agent.id)
    399 			|> Map.put(:receiver_id, agent.id)
    400 		assert {:error, "you don't have ownership over this resource"} =
    401 			Domain.create(params)
    402 	end
    403 
    404 	test "fail when event's unit and resource's unit differ", %{params: params} do
    405 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
    406 		assert {:error, "the unit of resource quantity must match with the unit of this resource"} =
    407 			Domain.create(params)
    408 	end
    409 
    410 	@tag :want_contained
    411 	test "fail when the resource is a contained resource", %{params: params} do
    412 		assert {:error, "you can't consume a contained resource"} = Domain.create(params)
    413 	end
    414 
    415 	@tag :want_container
    416 	test "fail when the resource is a container resource", %{params: params} do
    417 		assert {:error, "you can't consume a container resource"} = Domain.create(params)
    418 	end
    419 end
    420 
    421 describe "`create/2` with use:" do
    422 	setup %{res: res} do
    423 		%{params: %{
    424 			action_id: "use",
    425 			input_of_id: Factory.insert!(:process).id,
    426 			provider_id: Factory.insert!(:agent).id,
    427 			receiver_id: Factory.insert!(:agent).id,
    428 			resource_inventoried_as_id: res.id,
    429 			resource_quantity: %{
    430 				has_unit_id: res.accounting_quantity_has_unit_id,
    431 				has_numerical_value: Factory.decimal(),
    432 			},
    433 			effort_quantity: %{
    434 				has_unit_id: Factory.insert!(:unit).id,
    435 				has_numerical_value: Factory.decimal(),
    436 			},
    437 			has_point_in_time: Factory.now(),
    438 		}}
    439 	end
    440 
    441 	test "pass when all good", %{params: params} do
    442 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    443 	end
    444 
    445 	test "fail when the event's resource quantity unit doesn't match with the resource's", %{params: params} do
    446 		assert {:error, "the unit of resource quantity must match with the unit of this resource"} =
    447 			update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
    448 			|> Domain.create()
    449 	end
    450 
    451 	@tag :want_contained
    452 	test "fail when the resource is a contained resource", %{params: params} do
    453 		assert {:error, "you can't use a contained resource"} = Domain.create(params)
    454 	end
    455 
    456 	@tag :want_container
    457 	test "fail when the resource is a container resource", %{params: params} do
    458 		assert {:error, "you can't use a container resource"} = Domain.create(params)
    459 	end
    460 end
    461 
    462 describe "`create/2` with pickup:" do
    463 	setup %{res: res} do
    464 		%{params: %{
    465 			action_id: "pickup",
    466 			input_of_id: Factory.insert!(:process).id,
    467 			provider_id: res.custodian_id,
    468 			receiver_id: res.custodian_id,
    469 			resource_inventoried_as_id: res.id,
    470 			resource_quantity: %{
    471 				has_unit_id: res.onhand_quantity_has_unit_id,
    472 				has_numerical_value: res.onhand_quantity_has_numerical_value,
    473 			},
    474 			has_beginning: Factory.now(),
    475 		}}
    476 	end
    477 
    478 	test "pass when all good", %{params: params} do
    479 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    480 	end
    481 
    482 	test "fail when provider doesn't have custody over the resource", %{params: params} do
    483 		agent = Factory.insert!(:agent)
    484 		params =
    485 			params
    486 			|> Map.put(:provider_id, agent.id)
    487 			|> Map.put(:receiver_id, agent.id)
    488 		assert {:error, "you don't have custody over this resource"} =
    489 			Domain.create(params)
    490 	end
    491 
    492 	@tag :want_contained
    493 	test "fail when the resource is a contained resource", %{params: params} do
    494 		assert {:error, "you can't pickup a contained resource"} =
    495 			Domain.create(params)
    496 	end
    497 
    498 	test "fail when event's unit and resource's unit differ", %{params: params} do
    499 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
    500 		assert {:error, "the unit of resource quantity must match with the unit of this resource"} =
    501 			Domain.create(params)
    502 	end
    503 
    504 	test "fail when event's quantity value and resource's onhand-quantity value differ", %{params: params} do
    505 		params = update_in(params.resource_quantity.has_numerical_value, &Decimal.add(&1, 1))
    506 		assert {:error, "the pickup events need to fully pickup the resource"} =
    507 			Domain.create(params)
    508 	end
    509 
    510 	test "fail when more than one pickup event references the same resource in the same process", %{params: params} do
    511 		assert {:ok, _} = Domain.create(params)
    512 		assert {:error, "no more than one pickup event in the same process, referring to the same resource is allowed"}
    513 			= Domain.create(params)
    514 	end
    515 end
    516 
    517 describe "`create/2` with dropoff:" do
    518 	setup %{res: res} do
    519 		assert %EconomicEvent{} = pair_evt =
    520 			Domain.create!(%{
    521 				action_id: "pickup",
    522 				input_of_id: Factory.insert!(:process).id,
    523 				provider_id: res.custodian_id,
    524 				receiver_id: res.custodian_id,
    525 				resource_inventoried_as_id: res.id,
    526 				resource_quantity: %{
    527 					has_unit_id: res.onhand_quantity_has_unit_id,
    528 					has_numerical_value: res.onhand_quantity_has_numerical_value,
    529 				},
    530 				has_end: Factory.now(),
    531 			})
    532 
    533 		%{params: %{
    534 			action_id: "dropoff",
    535 			output_of_id: pair_evt.input_of_id,
    536 			provider_id: pair_evt.provider_id,
    537 			receiver_id: pair_evt.receiver_id,
    538 			resource_inventoried_as_id: pair_evt.resource_inventoried_as_id,
    539 			resource_quantity: %{
    540 				has_unit_id: pair_evt.resource_quantity_has_unit_id,
    541 				has_numerical_value: pair_evt.resource_quantity_has_numerical_value,
    542 			},
    543 			has_beginning: Factory.now(),
    544 			has_end: Factory.now(),
    545 			to_location_id: Factory.insert!(:spatial_thing).id,
    546 		}}
    547 	end
    548 
    549 	test "pass when all good", %{params: params} do
    550 			assert {:ok, %EconomicEvent{} = evt} = Domain.create(params)
    551 		evt = Domain.preload(evt, :resource_inventoried_as)
    552 		res = evt.resource_inventoried_as
    553 		assert res.current_location_id == params.to_location_id
    554 	end
    555 
    556 	test "fail when provider doesn't have custody over the resource", %{params: params} do
    557 		agent = Factory.insert!(:agent)
    558 		params =
    559 			params
    560 			|> Map.put(:provider_id, agent.id)
    561 			|> Map.put(:receiver_id, agent.id)
    562 		assert {:error, "you don't have custody over this resource"} =
    563 			Domain.create(params)
    564 	end
    565 
    566 	test "fail when event's unit and paired event's unit differ", %{params: params} do
    567 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
    568 		assert {:error, "the unit of resource quantity must match with the unit of the paired event"} =
    569 			Domain.create(params)
    570 	end
    571 
    572 	@tag :want_container
    573 	test "fail when the resource is a container and event's quantity value and resource's onhand-quantity value differ", %{params: params} do
    574 		params = update_in(params.resource_quantity.has_numerical_value, &Decimal.add(&1, 1))
    575 		assert {:error, "the dropoff events need to fully dropoff the resource"} =
    576 			Domain.create(params)
    577 	end
    578 
    579 	test "fail when more than one dropoff event references the same resource in the same process", %{params: params} do
    580 		assert {:ok, _} = Domain.create(params)
    581 		assert {:error, "no more than one dropoff event in the same process, referring to the same resource is allowed"}
    582 			= Domain.create(params)
    583 	end
    584 end
    585 
    586 describe "`create/2` with accept:" do
    587 	setup %{res: res} do
    588 		%{params: %{
    589 			action_id: "accept",
    590 			input_of_id: Factory.insert!(:process).id,
    591 			provider_id: res.custodian_id,
    592 			receiver_id: res.custodian_id,
    593 			resource_inventoried_as_id: res.id,
    594 			resource_quantity: %{
    595 				has_unit_id: res.onhand_quantity_has_unit_id,
    596 				has_numerical_value: res.onhand_quantity_has_numerical_value,
    597 			},
    598 			has_point_in_time: Factory.now(),
    599 		}}
    600 	end
    601 
    602 	test "pass when all good", %{params: params} do
    603 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    604 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    605 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    606 
    607 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
    608 			res_before.accounting_quantity_has_numerical_value)
    609 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
    610 			Decimal.sub(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    611 	end
    612 
    613 	test "fail when provider doesn't have custody over the resource", %{params: params} do
    614 		agent = Factory.insert!(:agent)
    615 		params =
    616 			params
    617 			|> Map.put(:provider_id, agent.id)
    618 			|> Map.put(:receiver_id, agent.id)
    619 		assert {:error, "you don't have custody over this resource"} =
    620 			Domain.create(params)
    621 	end
    622 
    623 	@tag :want_contained
    624 	test "fail when the resource is a contained resource", %{params: params} do
    625 		assert {:error, "you can't accept a contained resource"} =
    626 			Domain.create(params)
    627 	end
    628 
    629 	test "fail when event's unit and resource's unit differ", %{params: params} do
    630 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
    631 		assert {:error, "the unit of resource quantity must match with the unit of this resource"} =
    632 			Domain.create(params)
    633 	end
    634 
    635 	test "fail when event's quantity value and resource's onhand-quantity value differ", %{params: params} do
    636 		params = update_in(params.resource_quantity.has_numerical_value, &Decimal.add(&1, 1))
    637 		assert {:error, "the accept events need to fully accept the resource"} =
    638 			Domain.create(params)
    639 	end
    640 
    641 	@tag skip: "TODO: use combine-separate when implemented"
    642 	@tag :want_combine
    643 	test "fail when the there are any combine events", %{params: params} do
    644 		assert {:error, "you can't add another accept event to the same process where there are at least one combine or separate events"} =
    645 			Domain.create(params)
    646 	end
    647 
    648 	@tag skip: "TODO: use combine-separate when implemented"
    649 	@tag :want_combine
    650 	test "fail when the there are any separate events", %{params: params} do
    651 		assert {:error, "you can't add another accept event to the same process where there are at least one combine or separate events"} =
    652 			Domain.create(params)
    653 	end
    654 
    655 	test "fail when more than one accept event references the same resource in the same process", %{params: params} do
    656 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    657 
    658 		# in order to satisfy the fact that they it should fully
    659 		# accept the resource
    660 		params |> Map.put(:action_id, "raise") |> Domain.create()
    661 		assert {:error, "no more than one accept event in the same process, referring to the same resource is allowed"} =
    662 			Domain.create(params)
    663 	end
    664 end
    665 
    666 describe "`create/2` with modify:" do
    667 	setup %{res: res} do
    668 		assert %EconomicEvent{} = pair_evt =
    669 			Domain.create!(%{
    670 				action_id: "accept",
    671 				input_of_id: Factory.insert!(:process).id,
    672 				provider_id: res.custodian_id,
    673 				receiver_id: res.custodian_id,
    674 				resource_inventoried_as_id: res.id,
    675 				resource_quantity: %{
    676 					has_unit_id: res.onhand_quantity_has_unit_id,
    677 					has_numerical_value: res.onhand_quantity_has_numerical_value,
    678 				},
    679 				has_end: Factory.now(),
    680 			})
    681 
    682 		%{params: %{
    683 			action_id: "modify",
    684 			output_of_id: pair_evt.input_of_id,
    685 			provider_id: pair_evt.provider_id,
    686 			receiver_id: pair_evt.receiver_id,
    687 			resource_inventoried_as_id: pair_evt.resource_inventoried_as_id,
    688 			resource_quantity: %{
    689 				has_unit_id: pair_evt.resource_quantity_has_unit_id,
    690 				has_numerical_value: pair_evt.resource_quantity_has_numerical_value,
    691 			},
    692 			has_beginning: Factory.now(),
    693 			has_end: Factory.now(),
    694 		}}
    695 	end
    696 
    697 	test "pass when all good", %{params: params} do
    698 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    699 		assert res_before.stage_id == nil
    700 
    701 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    702 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    703 		proc = Process.Domain.one!(params.output_of_id)
    704 		assert res_after.stage_id == proc.based_on_id
    705 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
    706 			res_before.accounting_quantity_has_numerical_value)
    707 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
    708 			Decimal.add(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    709 	end
    710 
    711 	test "fail when provider doesn't have custody over the resource", %{params: params} do
    712 		agent = Factory.insert!(:agent)
    713 		params =
    714 			params
    715 			|> Map.put(:provider_id, agent.id)
    716 			|> Map.put(:receiver_id, agent.id)
    717 		assert {:error, "you don't have custody over this resource"} =
    718 			Domain.create(params)
    719 	end
    720 
    721 	test "fail when event's unit and paired event's unit differ", %{params: params} do
    722 		params = update_in(params.resource_quantity.has_unit_id, fn _ ->
    723 			Factory.insert!(:unit).id
    724 		end)
    725 		assert {:error, "the unit of resource quantity must match with the unit of the paired event"} =
    726 			Domain.create(params)
    727 	end
    728 
    729 	test "fail when event's quantity value and resource's onhand-quantity value differ", %{params: params} do
    730 		params = update_in(params.resource_quantity.has_numerical_value, &Decimal.add(&1, 1))
    731 		assert {:error, "the modify events need to fully modify the resource"} =
    732 			Domain.create(params)
    733 	end
    734 
    735 	test "fail when more than one modify event references the same resource in the same process", %{params: params} do
    736 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    737 
    738 		# in order to satisfy the fact that they it should fully
    739 		# modify the resource
    740 		params |> Map.put(:action_id, "raise") |> Domain.create!()
    741 		assert {:error, "no more than one modify event in the same process, referring to the same resource is allowed"} =
    742 			Domain.create(params)
    743 	end
    744 end
    745 
    746 describe "`create/2` with transferCustody:" do
    747 	setup %{res: res} = ctx do
    748 		if ctx[:want_to_resource] do
    749 			agent = Factory.insert!(:agent)
    750 			params = %{
    751 				action_id: "raise",
    752 				provider_id: agent.id,
    753 				receiver_id: agent.id,
    754 				resource_conforms_to_id: res.conforms_to_id,
    755 				resource_quantity: %{
    756 					has_unit_id: res.accounting_quantity_has_unit_id,
    757 					has_numerical_value: Factory.decimal(),
    758 				},
    759 				has_point_in_time: Factory.now(),
    760 			}
    761 			assert %EconomicEvent{resource_inventoried_as_id: to_res_id} =
    762 				Domain.create!(params, %{name: Factory.str("name")})
    763 
    764 			%{params: %{
    765 				action_id: "transferCustody",
    766 				provider_id: res.custodian_id,
    767 				receiver_id: Factory.insert!(:agent).id,
    768 				resource_inventoried_as_id: res.id,
    769 				to_resource_inventoried_as_id: to_res_id,
    770 				resource_quantity: %{
    771 					has_unit_id: res.onhand_quantity_has_unit_id,
    772 					has_numerical_value: res.onhand_quantity_has_numerical_value,
    773 				},
    774 				has_beginning: Factory.now(),
    775 			}}
    776 		else
    777 			%{params: %{
    778 				action_id: "transferCustody",
    779 				provider_id: res.custodian_id,
    780 				receiver_id: Factory.insert!(:agent).id,
    781 				resource_inventoried_as_id: res.id,
    782 				resource_quantity: %{
    783 					has_unit_id: res.onhand_quantity_has_unit_id,
    784 					has_numerical_value: res.onhand_quantity_has_numerical_value,
    785 				},
    786 				to_location_id: Factory.insert!(:spatial_thing).id,
    787 				has_beginning: Factory.now(),
    788 			}}
    789 		end
    790 	end
    791 
    792 	test "pass without `:to_resource_inventoried_as`", %{params: params} do
    793 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    794 
    795 		contained_ids = Enum.map(0..9, fn _ ->
    796 			agent = Factory.insert!(:agent)
    797 			raise_params = %{
    798 				action_id: "raise",
    799 				provider_id: agent.id,
    800 				receiver_id: agent.id,
    801 				resource_conforms_to_id: Factory.insert!(:resource_specification).id,
    802 				resource_quantity: %{
    803 					has_unit_id: Factory.insert!(:unit).id,
    804 					has_numerical_value: Factory.decimal(),
    805 				},
    806 				has_end: Factory.now(),
    807 			}
    808 			assert %EconomicEvent{} = evt =
    809 			Domain.create!(raise_params, %{name: Factory.str("name")})
    810 		evt = Domain.preload(evt, :resource_inventoried_as)
    811 			tmp_res = evt.resource_inventoried_as
    812 
    813 			Changeset.change(tmp_res, contained_in_id: params.resource_inventoried_as_id)
    814 			|> Repo.update!()
    815 
    816 			tmp_res.id
    817 		end)
    818 
    819 		res_params = %{
    820 			name: Factory.str("name"),
    821 			note: Factory.str("note"),
    822 			#image: Factory.img(),
    823 			tracking_identifier: Factory.str("tracking identifier"),
    824 			lot_id: Factory.insert!(:product_batch).id,
    825 			okhv: Factory.str("okhv"),
    826 			repo: Factory.uri(),
    827 			version: Factory.str("version"),
    828 			licensor: Factory.str("licensor"),
    829 			license: Factory.str("license"),
    830 			metadata: %{Factory.str("key") => Factory.str("val")},
    831 		}
    832 		assert {:ok, %EconomicEvent{} = evt} = Domain.create(params, res_params)
    833 		evt = Domain.preload(evt, :to_resource_inventoried_as)
    834 		to_res = evt.to_resource_inventoried_as
    835 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    836 
    837 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
    838 			res_before.accounting_quantity_has_numerical_value)
    839 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
    840 			Decimal.sub(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    841 
    842 		assert to_res.name == res_params.name
    843 		assert to_res.note == res_params.note
    844 		#assert to_res.image == res_params.image
    845 		assert to_res.tracking_identifier == res_params.tracking_identifier
    846 		assert to_res.lot_id == res_params.lot_id
    847 		assert to_res.okhv == res_params.okhv
    848 		assert to_res.repo == res_params.repo
    849 		assert to_res.version == res_params.version
    850 		assert to_res.licensor == res_params.licensor
    851 		assert to_res.license == res_params.license
    852 		assert to_res.metadata == res_params.metadata
    853 
    854 		assert to_res.primary_accountable_id == params.receiver_id
    855 		assert to_res.custodian_id == params.receiver_id
    856 		assert Decimal.eq?(to_res.accounting_quantity_has_numerical_value, 0)
    857 		assert to_res.accounting_quantity_has_unit_id == params.resource_quantity.has_unit_id
    858 		assert Decimal.eq?(to_res.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value)
    859 		assert to_res.onhand_quantity_has_unit_id == params.resource_quantity.has_unit_id
    860 		assert to_res.current_location_id == params.to_location_id
    861 
    862 		from(r in EconomicResource,
    863 			where: r.id in ^contained_ids,
    864 			select: map(r, ~w[custodian_id contained_in_id]a))
    865 		|> Repo.all()
    866 		|> Enum.each(fn r ->
    867 			assert r.custodian_id == evt.receiver_id
    868 			assert r.contained_in_id == to_res.id
    869 		end)
    870 	end
    871 
    872 	@tag :want_to_resource
    873 	test "pass with `:to_resource_inventoried_as`", %{params: params} do
    874 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    875 		to_res_before = EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
    876 
    877 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
    878 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    879 		to_res_after = EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
    880 
    881 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
    882 			res_before.accounting_quantity_has_numerical_value)
    883 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
    884 			Decimal.sub(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    885 
    886 		assert Decimal.eq?(to_res_after.accounting_quantity_has_numerical_value,
    887 			to_res_before.accounting_quantity_has_numerical_value)
    888 		assert Decimal.eq?(to_res_after.onhand_quantity_has_numerical_value,
    889 			Decimal.add(to_res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
    890 	end
    891 
    892 	test "fail when provider doesn't have custody over the resource", %{params: params} do
    893 		agent = Factory.insert!(:agent)
    894 		params =
    895 			params
    896 			|> Map.put(:provider_id, agent.id)
    897 			|> Map.put(:receiver_id, agent.id)
    898 		assert {:error, "you don't have custody over this resource"} =
    899 			Domain.create(params)
    900 	end
    901 
    902 	@tag :want_contained
    903 	test "fail when the resource is a contained resource", %{params: params} do
    904 		assert {:error, "you can't transfer-custody a contained resource"} =
    905 			Domain.create(params)
    906 	end
    907 
    908 	test "fail when event's unit and resource's unit differ", %{params: params} do
    909 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
    910 		assert {:error, "the unit of resource-quantity must match with the unit of resource-inventoried-as"} =
    911 			Domain.create(params)
    912 	end
    913 
    914 	@tag :want_container
    915 	test "fail when the resource is a container and onhand-quantity is non-positive", %{params: params} do
    916 		err = "the transfer-custody events need container resources to have positive onhand-quantity"
    917 		res = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
    918 
    919 		Changeset.change(res, onhand_quantity_has_numerical_value: 0.0) |> Repo.update!()
    920 		assert {:error, ^err} = Domain.create(params)
    921 
    922 		Changeset.change(res, onhand_quantity_has_numerical_value: -1.0) |> Repo.update!()
    923 		assert {:error, ^err} = Domain.create(params)
    924 	end
    925 
    926 	@tag :want_container
    927 	test "fail when event's quantity value and resource's onhand-quantity value differ", %{params: params} do
    928 		params = update_in(params.resource_quantity.has_numerical_value, &Decimal.add(&1, 1))
    929 		assert {:error, "the transfer-custody events need to fully transfer the resource"} =
    930 			Domain.create(params)
    931 	end
    932 
    933 	@tag :want_container
    934 	@tag :want_to_resource
    935 	test "fail when transferring a container resource into another resource", %{params: params} do
    936 		assert {:error, "you can't transfer-custody a container resource into another resource"} =
    937 			Domain.create(params)
    938 	end
    939 
    940 	@tag :want_to_resource
    941 	test "fail when the to-resource is a contained resource", %{params: params} do
    942 		agent = Factory.insert!(:agent)
    943 		raise_params = %{
    944 			action_id: "raise",
    945 			provider_id: agent.id,
    946 			receiver_id: agent.id,
    947 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
    948 			resource_quantity: %{
    949 				has_unit_id: Factory.insert!(:unit).id,
    950 				has_numerical_value: Factory.decimal(),
    951 			},
    952 			has_end: Factory.now(),
    953 		}
    954 		assert {:ok, %EconomicEvent{resource_inventoried_as_id: tmp_res_id}} =
    955 			Domain.create(raise_params, %{name: Factory.str("name")})
    956 
    957 		# TODO: use combine-separate when implemented instead
    958 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
    959 		|> Changeset.change(contained_in_id: tmp_res_id)
    960 		|> Repo.update!()
    961 
    962 		assert {:error, "you can't transfer-custody into a contained resource"} =
    963 			Domain.create(params)
    964 	end
    965 
    966 	@tag :want_to_resource
    967 	test "fail when the to-resource is a container resource", %{params: params} do
    968 		agent = Factory.insert!(:agent)
    969 		raise_params = %{
    970 			action_id: "raise",
    971 			provider_id: agent.id,
    972 			receiver_id: agent.id,
    973 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
    974 			resource_quantity: %{
    975 				has_unit_id: Factory.insert!(:unit).id,
    976 				has_numerical_value: Factory.decimal(),
    977 			},
    978 			has_end: Factory.now(),
    979 		}
    980 		assert {:ok, %EconomicEvent{} = evt} =
    981 			Domain.create(raise_params, %{name: Factory.str("name")})
    982 		evt = Domain.preload(evt, :resource_inventoried_as)
    983 		tmp_res = evt.resource_inventoried_as
    984 		# TODO: use combine-separate when implemented instead
    985 		Changeset.change(tmp_res, contained_in_id: params.to_resource_inventoried_as_id)
    986 		|> Repo.update!()
    987 
    988 		assert {:error, "you can't transfer-custody into a container resource"} =
    989 			Domain.create(params)
    990 	end
    991 
    992 	@tag :want_to_resource
    993 	test "fail when event's unit and to-resource's unit differ", %{params: params} do
    994 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
    995 		|> Changeset.change(onhand_quantity_has_unit_id: Factory.insert!(:unit).id)
    996 		|> Repo.update!()
    997 
    998 		assert {:error, "the unit of resource-quantity must match with the unit of to-resource-inventoried-as"} =
    999 			Domain.create(params)
   1000 	end
   1001 
   1002 	@tag :want_to_resource
   1003 	test "fail when resoure and to-resource don't conform to the same spec", %{params: params} do
   1004 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1005 		|> Changeset.change(conforms_to_id: Factory.insert!(:resource_specification).id)
   1006 		|> Repo.update!()
   1007 
   1008 		assert {:error, "the resources must conform to the same specification"} =
   1009 			Domain.create(params)
   1010 	end
   1011 end
   1012 
   1013 describe "`create/2` with transferAllRights:" do
   1014 	setup %{res: res} = ctx do
   1015 		if ctx[:want_to_resource] do
   1016 			agent = Factory.insert!(:agent)
   1017 			params = %{
   1018 				action_id: "raise",
   1019 				provider_id: agent.id,
   1020 				receiver_id: agent.id,
   1021 				resource_conforms_to_id: res.conforms_to_id,
   1022 				resource_quantity: %{
   1023 					has_unit_id: res.accounting_quantity_has_unit_id,
   1024 					has_numerical_value: Factory.decimal(),
   1025 				},
   1026 				has_point_in_time: Factory.now(),
   1027 			}
   1028 			assert %EconomicEvent{resource_inventoried_as_id: to_res_id} =
   1029 				Domain.create!(params, %{name: Factory.str("name")})
   1030 
   1031 			%{params: %{
   1032 				action_id: "transferAllRights",
   1033 				provider_id: res.primary_accountable_id,
   1034 				receiver_id: Factory.insert!(:agent).id,
   1035 				resource_inventoried_as_id: res.id,
   1036 				to_resource_inventoried_as_id: to_res_id,
   1037 				resource_quantity: %{
   1038 					has_unit_id: res.accounting_quantity_has_unit_id,
   1039 					has_numerical_value: res.accounting_quantity_has_numerical_value,
   1040 				},
   1041 				has_beginning: Factory.now(),
   1042 			}}
   1043 		else
   1044 			%{params: %{
   1045 				action_id: "transferAllRights",
   1046 				provider_id: res.primary_accountable_id,
   1047 				receiver_id: Factory.insert!(:agent).id,
   1048 				resource_inventoried_as_id: res.id,
   1049 				resource_quantity: %{
   1050 					has_unit_id: res.accounting_quantity_has_unit_id,
   1051 					has_numerical_value: res.accounting_quantity_has_numerical_value,
   1052 				},
   1053 				has_beginning: Factory.now(),
   1054 			}}
   1055 		end
   1056 	end
   1057 
   1058 	test "pass without `:to_resource_inventoried_as`", %{params: params} do
   1059 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1060 
   1061 		contained_ids = Enum.map(0..9, fn _ ->
   1062 			agent = Factory.insert!(:agent)
   1063 			raise_params = %{
   1064 				action_id: "raise",
   1065 				provider_id: agent.id,
   1066 				receiver_id: agent.id,
   1067 				resource_conforms_to_id: Factory.insert!(:resource_specification).id,
   1068 				resource_quantity: %{
   1069 					has_unit_id: Factory.insert!(:unit).id,
   1070 					has_numerical_value: Factory.decimal(),
   1071 				},
   1072 				has_end: Factory.now(),
   1073 			}
   1074 			assert {:ok, %EconomicEvent{} = evt} =
   1075 			Domain.create(raise_params, %{name: Factory.str("name")})
   1076 		evt = Domain.preload(evt, :resource_inventoried_as)
   1077 			tmp_res = evt.resource_inventoried_as
   1078 			Changeset.change(tmp_res, contained_in_id: params.resource_inventoried_as_id)
   1079 			|> Repo.update!()
   1080 
   1081 			tmp_res.id
   1082 		end)
   1083 
   1084 		res_params = %{
   1085 			name: Factory.str("name"),
   1086 			note: Factory.str("note"),
   1087 			#image: Factory.img(),
   1088 			tracking_identifier: Factory.str("tracking identifier"),
   1089 			lot_id: Factory.insert!(:product_batch).id,
   1090 			okhv: Factory.str("okhv"),
   1091 			repo: Factory.uri(),
   1092 			version: Factory.str("version"),
   1093 			licensor: Factory.str("licensor"),
   1094 			license: Factory.str("license"),
   1095 			metadata: %{Factory.str("key") => Factory.str("val")},
   1096 		}
   1097 		assert {:ok, %EconomicEvent{} = evt} =
   1098 			Domain.create(params, res_params)
   1099 		evt = Domain.preload(evt, :to_resource_inventoried_as)
   1100 		to_res = evt.to_resource_inventoried_as
   1101 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1102 
   1103 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
   1104 			Decimal.sub(res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1105 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
   1106 			res_before.onhand_quantity_has_numerical_value)
   1107 
   1108 		assert to_res.name == res_params.name
   1109 		assert to_res.note == res_params.note
   1110 		#assert to_res.image == res_params.image
   1111 		assert to_res.tracking_identifier == res_params.tracking_identifier
   1112 		assert to_res.lot_id == res_params.lot_id
   1113 		assert to_res.okhv == res_params.okhv
   1114 		assert to_res.repo == res_params.repo
   1115 		assert to_res.version == res_params.version
   1116 		assert to_res.licensor == res_params.licensor
   1117 		assert to_res.license == res_params.license
   1118 		assert to_res.metadata == res_params.metadata
   1119 
   1120 		assert to_res.primary_accountable_id == params.receiver_id
   1121 		assert to_res.custodian_id == params.receiver_id
   1122 		assert Decimal.eq?(to_res.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value)
   1123 		assert to_res.accounting_quantity_has_unit_id == params.resource_quantity.has_unit_id
   1124 		assert Decimal.eq?(to_res.onhand_quantity_has_numerical_value, 0)
   1125 		assert to_res.onhand_quantity_has_unit_id == params.resource_quantity.has_unit_id
   1126 
   1127 		from(r in EconomicResource,
   1128 			where: r.id in ^contained_ids,
   1129 			select: map(r, ~w[primary_accountable_id contained_in_id]a))
   1130 		|> Repo.all()
   1131 		|> Enum.each(fn r ->
   1132 			assert r.primary_accountable_id == evt.receiver_id
   1133 			assert r.contained_in_id == to_res.id
   1134 		end)
   1135 	end
   1136 
   1137 	@tag :want_to_resource
   1138 	test "pass with `:to_resource_inventoried_as`", %{params: params} do
   1139 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1140 		to_res_before = EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1141 
   1142 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
   1143 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1144 		to_res_after = EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1145 
   1146 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
   1147 			Decimal.sub(res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1148 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
   1149 			res_before.onhand_quantity_has_numerical_value)
   1150 
   1151 		assert Decimal.eq?(to_res_after.accounting_quantity_has_numerical_value,
   1152 			Decimal.add(to_res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1153 		assert Decimal.eq?(to_res_after.onhand_quantity_has_numerical_value,
   1154 			to_res_before.onhand_quantity_has_numerical_value)
   1155 	end
   1156 
   1157 	test "fail when provider doesn't have accountability over the resource", %{params: params} do
   1158 		agent = Factory.insert!(:agent)
   1159 		params =
   1160 			params
   1161 			|> Map.put(:provider_id, agent.id)
   1162 			|> Map.put(:receiver_id, agent.id)
   1163 		assert {:error, "you don't have accountability over this resource"} =
   1164 			Domain.create(params)
   1165 	end
   1166 
   1167 	@tag :want_contained
   1168 	test "fail when the resource is a contained resource", %{params: params} do
   1169 		assert {:error, "you can't transfer-all-rights a contained resource"} =
   1170 			Domain.create(params)
   1171 	end
   1172 
   1173 	test "fail when event's unit and resource's unit differ", %{params: params} do
   1174 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
   1175 		assert {:error, "the unit of resource-quantity must match with the unit of resource-inventoried-as"} =
   1176 			Domain.create(params)
   1177 	end
   1178 
   1179 	@tag :want_container
   1180 	test "fail when the resource is a container and accounting-quantity is non-positive", %{params: params} do
   1181 		err = "the transfer-all-rights events need container resources to have positive accounting-quantity"
   1182 		res = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1183 
   1184 		Changeset.change(res, accounting_quantity_has_numerical_value: Decimal.new(0)) |> Repo.update!()
   1185 		assert {:error, ^err} = Domain.create(params)
   1186 
   1187 		Changeset.change(res, accounting_quantity_has_numerical_value: Decimal.new(-1)) |> Repo.update!()
   1188 		assert {:error, ^err} = Domain.create(params)
   1189 	end
   1190 
   1191 	@tag :want_container
   1192 	test "fail when event's quantity value and resource's accounting-quantity value differ", %{params: params} do
   1193 		params = update_in(params.resource_quantity.has_numerical_value, &Decimal.add(&1, 1))
   1194 		assert {:error, "the transfer-all-rights events need to fully transfer the resource"} =
   1195 			Domain.create(params)
   1196 	end
   1197 
   1198 	@tag :want_container
   1199 	@tag :want_to_resource
   1200 	test "fail when transferring a container resource into another resource", %{params: params} do
   1201 		assert {:error, "you can't transfer-all-rights a container resource into another resource"} =
   1202 			Domain.create(params)
   1203 	end
   1204 
   1205 	@tag :want_to_resource
   1206 	test "fail when the to-resource is a contained resource", %{params: params} do
   1207 		agent = Factory.insert!(:agent)
   1208 		raise_params = %{
   1209 			action_id: "raise",
   1210 			provider_id: agent.id,
   1211 			receiver_id: agent.id,
   1212 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
   1213 			resource_quantity: %{
   1214 				has_unit_id: Factory.insert!(:unit).id,
   1215 				has_numerical_value: Factory.decimal(),
   1216 			},
   1217 			has_end: Factory.now(),
   1218 		}
   1219 		assert {:ok, %EconomicEvent{resource_inventoried_as_id: tmp_res_id}} =
   1220 			Domain.create(raise_params, %{name: Factory.str("name")})
   1221 
   1222 		# TODO: use combine-separate when implemented instead
   1223 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1224 		|> Changeset.change(contained_in_id: tmp_res_id)
   1225 		|> Repo.update!()
   1226 
   1227 		assert {:error, "you can't transfer-all-rights into a contained resource"} =
   1228 			Domain.create(params)
   1229 	end
   1230 
   1231 	@tag :want_to_resource
   1232 	test "fail when the to-resource is a container resource", %{params: params} do
   1233 		agent = Factory.insert!(:agent)
   1234 		raise_params = %{
   1235 			action_id: "raise",
   1236 			provider_id: agent.id,
   1237 			receiver_id: agent.id,
   1238 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
   1239 			resource_quantity: %{
   1240 				has_unit_id: Factory.insert!(:unit).id,
   1241 				has_numerical_value: Factory.decimal(),
   1242 			},
   1243 			has_end: Factory.now(),
   1244 		}
   1245 		assert {:ok, %EconomicEvent{} = evt} =
   1246 			Domain.create(raise_params, %{name: Factory.str("name")})
   1247 		evt = Domain.preload(evt, :resource_inventoried_as)
   1248 		tmp_res = evt.resource_inventoried_as
   1249 		# TODO: use combine-separate when implemented instead
   1250 		Changeset.change(tmp_res, contained_in_id: params.to_resource_inventoried_as_id)
   1251 		|> Repo.update()
   1252 
   1253 		assert {:error, "you can't transfer-all-rights into a container resource"} =
   1254 			Domain.create(params)
   1255 	end
   1256 
   1257 	@tag :want_to_resource
   1258 	test "fail when event's unit and to-resource's unit differ", %{params: params} do
   1259 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1260 		|> Changeset.change(accounting_quantity_has_unit_id: Factory.insert!(:unit).id)
   1261 		|> Repo.update!()
   1262 
   1263 		assert {:error, "the unit of resource-quantity must match with the unit of to-resource-inventoried-as"} =
   1264 			Domain.create(params)
   1265 	end
   1266 
   1267 	@tag :want_to_resource
   1268 	test "fail when resoure and to-resource don't conform to the same spec", %{params: params} do
   1269 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1270 		|> Changeset.change(conforms_to_id: Factory.insert!(:resource_specification).id)
   1271 		|> Repo.update!()
   1272 
   1273 		assert {:error, "the resources must conform to the same specification"} =
   1274 			Domain.create(params)
   1275 	end
   1276 end
   1277 
   1278 describe "`create/2` with transfer:" do
   1279 	setup %{res: res} = ctx do
   1280 		if ctx[:want_to_resource] do
   1281 			agent = Factory.insert!(:agent)
   1282 			params = %{
   1283 				action_id: "raise",
   1284 				provider_id: agent.id,
   1285 				receiver_id: agent.id,
   1286 				resource_conforms_to_id: res.conforms_to_id,
   1287 				resource_quantity: %{
   1288 					has_unit_id: res.accounting_quantity_has_unit_id,
   1289 					has_numerical_value: Factory.decimal(),
   1290 				},
   1291 				has_point_in_time: Factory.now(),
   1292 			}
   1293 			assert %EconomicEvent{resource_inventoried_as_id: to_res_id} =
   1294 				Domain.create!(params, %{name: Factory.str("name")})
   1295 
   1296 			%{params: %{
   1297 				action_id: "transfer",
   1298 				provider_id: res.primary_accountable_id,
   1299 				receiver_id: Factory.insert!(:agent).id,
   1300 				resource_inventoried_as_id: res.id,
   1301 				to_resource_inventoried_as_id: to_res_id,
   1302 				resource_quantity: %{
   1303 					has_unit_id: res.accounting_quantity_has_unit_id,
   1304 					has_numerical_value: res.accounting_quantity_has_numerical_value,
   1305 				},
   1306 				has_beginning: Factory.now(),
   1307 			}}
   1308 		else
   1309 			%{params: %{
   1310 				action_id: "transfer",
   1311 				provider_id: res.primary_accountable_id,
   1312 				receiver_id: Factory.insert!(:agent).id,
   1313 				resource_inventoried_as_id: res.id,
   1314 				resource_quantity: %{
   1315 					has_unit_id: res.accounting_quantity_has_unit_id,
   1316 					has_numerical_value: res.accounting_quantity_has_numerical_value,
   1317 				},
   1318 				has_beginning: Factory.now(),
   1319 			}}
   1320 		end
   1321 	end
   1322 
   1323 	test "pass without `:to_resource_inventoried_as`", %{params: params} do
   1324 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1325 
   1326 		contained_ids = Enum.map(0..9, fn _ ->
   1327 			agent = Factory.insert!(:agent)
   1328 			raise_params = %{
   1329 				action_id: "raise",
   1330 				provider_id: agent.id,
   1331 				receiver_id: agent.id,
   1332 				resource_conforms_to_id: Factory.insert!(:resource_specification).id,
   1333 				resource_quantity: %{
   1334 					has_unit_id: Factory.insert!(:unit).id,
   1335 					has_numerical_value: Factory.decimal(),
   1336 				},
   1337 				has_end: Factory.now(),
   1338 			}
   1339 			assert {:ok, %EconomicEvent{} = evt} =
   1340 				Domain.create(raise_params, %{name: Factory.str("name")})
   1341 			evt = Domain.preload(evt, :resource_inventoried_as)
   1342 			tmp_res = evt.resource_inventoried_as
   1343 			Changeset.change(tmp_res, contained_in_id: params.resource_inventoried_as_id)
   1344 			|> Repo.update!()
   1345 
   1346 			tmp_res.id
   1347 		end)
   1348 
   1349 		res_params = %{
   1350 			name: Factory.str("name"),
   1351 			note: Factory.str("note"),
   1352 			#image: Factory.img(),
   1353 			tracking_identifier: Factory.str("tracking identifier"),
   1354 			lot_id: Factory.insert!(:product_batch).id,
   1355 			okhv: Factory.str("okhv"),
   1356 			repo: Factory.uri(),
   1357 			version: Factory.str("version"),
   1358 			licensor: Factory.str("licensor"),
   1359 			license: Factory.str("license"),
   1360 			metadata: %{Factory.str("key") => Factory.str("val")},
   1361 		}
   1362 		assert {:ok, %EconomicEvent{} = evt}
   1363 			= Domain.create(
   1364 				params,
   1365 				res_params)
   1366 		evt = Domain.preload(evt, :to_resource_inventoried_as)
   1367 		to_res = evt.to_resource_inventoried_as
   1368 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1369 
   1370 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
   1371 			Decimal.sub(res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1372 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
   1373 			Decimal.sub(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1374 
   1375 		assert to_res.name == res_params.name
   1376 		assert to_res.note == res_params.note
   1377 		#assert to_res.image == res_params.image
   1378 		assert to_res.tracking_identifier == res_params.tracking_identifier
   1379 		assert to_res.lot_id == res_params.lot_id
   1380 		assert to_res.okhv == res_params.okhv
   1381 		assert to_res.repo == res_params.repo
   1382 		assert to_res.version == res_params.version
   1383 		assert to_res.licensor == res_params.licensor
   1384 		assert to_res.license == res_params.license
   1385 		assert to_res.metadata == res_params.metadata
   1386 
   1387 		assert to_res.primary_accountable_id == params.receiver_id
   1388 		assert to_res.custodian_id == params.receiver_id
   1389 		assert Decimal.eq?(to_res.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value)
   1390 		assert to_res.accounting_quantity_has_unit_id == params.resource_quantity.has_unit_id
   1391 		assert Decimal.eq?(to_res.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value)
   1392 		assert to_res.onhand_quantity_has_unit_id == params.resource_quantity.has_unit_id
   1393 
   1394 		from(r in EconomicResource,
   1395 			where: r.id in ^contained_ids,
   1396 			select: map(r, ~w[primary_accountable_id custodian_id contained_in_id]a))
   1397 		|> Repo.all()
   1398 		|> Enum.each(fn r ->
   1399 			assert r.primary_accountable_id == evt.receiver_id
   1400 			assert r.custodian_id == evt.receiver_id
   1401 			assert r.contained_in_id == to_res.id
   1402 		end)
   1403 	end
   1404 
   1405 	@tag :want_to_resource
   1406 	test "pass with `:to_resource_inventoried_as`", %{params: params} do
   1407 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1408 		to_res_before = EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1409 
   1410 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
   1411 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1412 		to_res_after = EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1413 
   1414 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
   1415 			Decimal.sub(res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1416 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
   1417 			Decimal.sub(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1418 
   1419 		assert Decimal.eq?(to_res_after.accounting_quantity_has_numerical_value,
   1420 			Decimal.add(to_res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1421 		assert Decimal.eq?(to_res_after.onhand_quantity_has_numerical_value,
   1422 			Decimal.add(to_res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1423 	end
   1424 
   1425 	test "fail when provider doesn't have accountability over the resource", %{params: params} do
   1426 		EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1427 		|> Changeset.change(primary_accountable_id: Factory.insert!(:agent).id)
   1428 		|> Repo.update!()
   1429 
   1430 		assert {:error, "you don't have accountability over this resource"} =
   1431 			Domain.create(params)
   1432 	end
   1433 
   1434 	test "fail when provider doesn't have custody over the resource", %{params: params} do
   1435 		EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1436 		|> Changeset.change(custodian_id: Factory.insert!(:agent).id)
   1437 		|> Repo.update!()
   1438 
   1439 		assert {:error, "you don't have custody over this resource"} =
   1440 			Domain.create(params)
   1441 	end
   1442 
   1443 	@tag :want_contained
   1444 	test "fail when the resource is a contained resource", %{params: params} do
   1445 		assert {:error, "you can't transfer a contained resource"} =
   1446 			Domain.create(params)
   1447 	end
   1448 
   1449 	test "fail when event's unit and resource's unit differ", %{params: params} do
   1450 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
   1451 		assert {:error, "the unit of resource-quantity must match with the unit of resource-inventoried-as"} =
   1452 			Domain.create(params)
   1453 	end
   1454 
   1455 	@tag :want_to_resource
   1456 	test "fail when event's unit and to-resource's unit differ", %{params: params} do
   1457 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1458 		|> Changeset.change(accounting_quantity_has_unit_id: Factory.insert!(:unit).id)
   1459 		|> Repo.update!()
   1460 
   1461 		assert {:error, "the unit of resource-quantity must match with the unit of to-resource-inventoried-as"} =
   1462 			Domain.create(params)
   1463 	end
   1464 
   1465 	@tag :want_container
   1466 	test "fail when the resource is a container and accounting-quantity is non-positive", %{params: params} do
   1467 		err = "the transfer events need container resources to have positive accounting-quantity"
   1468 		res = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1469 
   1470 		Changeset.change(res, accounting_quantity_has_numerical_value: Decimal.new(0))
   1471 		|> Repo.update!()
   1472 		assert {:error, ^err} = Domain.create(params)
   1473 
   1474 		Changeset.change(res, accounting_quantity_has_numerical_value: Decimal.new(-1)) |> Repo.update!()
   1475 		assert {:error, ^err} = Domain.create(params)
   1476 	end
   1477 
   1478 	@tag :want_container
   1479 	test "fail when the resource is a container and onhand-quantity is non-positive", %{params: params} do
   1480 		err = "the transfer events need container resources to have positive onhand-quantity"
   1481 		res = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1482 
   1483 		Changeset.change(res, onhand_quantity_has_numerical_value: Decimal.new(0))
   1484 		|> Repo.update!()
   1485 		assert {:error, ^err} = Domain.create(params)
   1486 
   1487 		Changeset.change(res, onhand_quantity_has_numerical_value: Decimal.new(-1))
   1488 		|> Repo.update!()
   1489 		assert {:error, ^err} = Domain.create(params)
   1490 	end
   1491 
   1492 	@tag :want_container
   1493 	test "fail when event's quantity value and resource's accounting-quantity value differ", %{params: params} do
   1494 		EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1495 		|> Changeset.change(accounting_quantity_has_numerical_value: Decimal.add(params.resource_quantity.has_numerical_value, 1))
   1496 		|> Repo.update!()
   1497 
   1498 		assert {:error, "the transfer events need to fully transfer the resource"} =
   1499 			Domain.create(params)
   1500 	end
   1501 
   1502 	@tag :want_container
   1503 	test "fail when event's quantity value and resource's onhnad-quantity value differ", %{params: params} do
   1504 		EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1505 		|> Changeset.change(onhand_quantity_has_numerical_value: Decimal.add(params.resource_quantity.has_numerical_value, 1))
   1506 		|> Repo.update!()
   1507 		assert {:error, "the transfer events need to fully transfer the resource"} =
   1508 			Domain.create(params)
   1509 	end
   1510 
   1511 	@tag :want_container
   1512 	@tag :want_to_resource
   1513 	test "fail when transferring a container resource into another resource", %{params: params} do
   1514 		assert {:error, "you can't transfer a container resource into another resource"} =
   1515 			Domain.create(params)
   1516 	end
   1517 
   1518 	@tag :want_to_resource
   1519 	test "fail when the to-resource is a contained resource", %{params: params} do
   1520 		agent = Factory.insert!(:agent)
   1521 		raise_params = %{
   1522 			action_id: "raise",
   1523 			provider_id: agent.id,
   1524 			receiver_id: agent.id,
   1525 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
   1526 			resource_quantity: %{
   1527 				has_unit_id: Factory.insert!(:unit).id,
   1528 				has_numerical_value: Factory.decimal(),
   1529 			},
   1530 			has_end: Factory.now(),
   1531 		}
   1532 		assert {:ok, %EconomicEvent{resource_inventoried_as_id: tmp_res_id}} =
   1533 			Domain.create(raise_params, %{name: Factory.str("name")})
   1534 
   1535 		# TODO: use combine-separate when implemented instead
   1536 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1537 		|> Changeset.change(contained_in_id: tmp_res_id)
   1538 		|> Repo.update!()
   1539 
   1540 		assert {:error, "you can't transfer into a contained resource"} =
   1541 			Domain.create(params)
   1542 	end
   1543 
   1544 	@tag :want_to_resource
   1545 	test "fail when the to-resource is a container resource", %{params: params} do
   1546 		agent = Factory.insert!(:agent)
   1547 		raise_params = %{
   1548 			action_id: "raise",
   1549 			provider_id: agent.id,
   1550 			receiver_id: agent.id,
   1551 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
   1552 			resource_quantity: %{
   1553 				has_unit_id: Factory.insert!(:unit).id,
   1554 				has_numerical_value: Factory.decimal(),
   1555 			},
   1556 			has_end: Factory.now(),
   1557 		}
   1558 		assert {:ok, %EconomicEvent{} = evt} =
   1559 			Domain.create(raise_params, %{name: Factory.str("name")})
   1560 		evt = Domain.preload(evt, :resource_inventoried_as)
   1561 		tmp_res = evt.resource_inventoried_as
   1562 		# TODO: use combine-separate when implemented instead
   1563 		Changeset.change(tmp_res, contained_in_id: params.to_resource_inventoried_as_id)
   1564 		|> Repo.update()
   1565 
   1566 		assert {:error, "you can't transfer into a container resource"} =
   1567 			Domain.create(params)
   1568 	end
   1569 
   1570 	@tag :want_to_resource
   1571 	test "fail when resoure and to-resource don't conform to the same spec", %{params: params} do
   1572 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1573 		|> Changeset.change(conforms_to_id: Factory.insert!(:resource_specification).id)
   1574 		|> Repo.update!()
   1575 
   1576 		assert {:error, "the resources must conform to the same specification"} =
   1577 			Domain.create(params)
   1578 	end
   1579 end
   1580 
   1581 describe "`create/2` with move:" do
   1582 	setup %{res: res} = ctx do
   1583 		if ctx[:want_to_resource] do
   1584 			params = %{
   1585 				action_id: "raise",
   1586 				provider_id: res.primary_accountable_id,
   1587 				receiver_id: res.custodian_id,
   1588 				resource_conforms_to_id: res.conforms_to_id,
   1589 				resource_quantity: %{
   1590 					has_unit_id: res.accounting_quantity_has_unit_id,
   1591 					has_numerical_value: Factory.decimal(),
   1592 				},
   1593 				has_point_in_time: Factory.now(),
   1594 			}
   1595 			assert %EconomicEvent{resource_inventoried_as_id: to_res_id} =
   1596 				Domain.create!(params, %{name: Factory.str("name")})
   1597 
   1598 			%{params: %{
   1599 				action_id: "move",
   1600 				provider_id: res.primary_accountable_id,
   1601 				receiver_id: res.custodian_id,
   1602 				resource_inventoried_as_id: res.id,
   1603 				to_resource_inventoried_as_id: to_res_id,
   1604 				resource_quantity: %{
   1605 					has_unit_id: res.accounting_quantity_has_unit_id,
   1606 					has_numerical_value: res.accounting_quantity_has_numerical_value,
   1607 				},
   1608 				has_beginning: Factory.now(),
   1609 			}}
   1610 		else
   1611 			%{params: %{
   1612 				action_id: "move",
   1613 				provider_id: res.primary_accountable_id,
   1614 				receiver_id: res.custodian_id,
   1615 				resource_inventoried_as_id: res.id,
   1616 				resource_quantity: %{
   1617 					has_unit_id: res.accounting_quantity_has_unit_id,
   1618 					has_numerical_value: res.accounting_quantity_has_numerical_value,
   1619 				},
   1620 				has_beginning: Factory.now(),
   1621 			}}
   1622 		end
   1623 	end
   1624 
   1625 	test "pass without `:to_resource_inventoried_as`", %{params: params} do
   1626 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1627 
   1628 		contained_ids = Enum.map(0..9, fn _ ->
   1629 			agent = Factory.insert!(:agent)
   1630 			raise_params = %{
   1631 				action_id: "raise",
   1632 				provider_id: agent.id,
   1633 				receiver_id: agent.id,
   1634 				resource_conforms_to_id: Factory.insert!(:resource_specification).id,
   1635 				resource_quantity: %{
   1636 					has_unit_id: Factory.insert!(:unit).id,
   1637 					has_numerical_value: Factory.decimal(),
   1638 				},
   1639 				has_end: Factory.now(),
   1640 			}
   1641 			assert {:ok, %EconomicEvent{} = evt} =
   1642 			Domain.create(raise_params, %{name: Factory.str("name")})
   1643 		evt = Domain.preload(evt, :resource_inventoried_as)
   1644 			tmp_res = evt.resource_inventoried_as
   1645 			Changeset.change(tmp_res, contained_in_id: params.resource_inventoried_as_id)
   1646 			|> Repo.update!()
   1647 
   1648 			tmp_res.id
   1649 		end)
   1650 
   1651 		res_params = %{
   1652 			name: Factory.str("name"),
   1653 			note: Factory.str("note"),
   1654 			#image: Factory.img(),
   1655 			tracking_identifier: Factory.str("tracking identifier"),
   1656 			lot_id: Factory.insert!(:product_batch).id,
   1657 			okhv: Factory.str("okhv"),
   1658 			repo: Factory.uri(),
   1659 			version: Factory.str("version"),
   1660 			licensor: Factory.str("licensor"),
   1661 			license: Factory.str("license"),
   1662 			metadata: %{Factory.str("key") => Factory.str("val")},
   1663 		}
   1664 		assert {:ok, %EconomicEvent{} = evt} =
   1665 			Domain.create(params, res_params)
   1666 		evt = Domain.preload(evt, :to_resource_inventoried_as)
   1667 		to_res = evt.to_resource_inventoried_as
   1668 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1669 
   1670 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
   1671 			Decimal.sub(res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1672 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
   1673 			Decimal.sub(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1674 
   1675 		assert to_res.name == res_params.name
   1676 		assert to_res.note == res_params.note
   1677 		#assert to_res.image == res_params.image
   1678 		assert to_res.tracking_identifier == res_params.tracking_identifier
   1679 		assert to_res.lot_id == res_params.lot_id
   1680 		assert to_res.okhv == res_params.okhv
   1681 		assert to_res.repo == res_params.repo
   1682 		assert to_res.version == res_params.version
   1683 		assert to_res.licensor == res_params.licensor
   1684 		assert to_res.license == res_params.license
   1685 		assert to_res.metadata == res_params.metadata
   1686 
   1687 		assert to_res.primary_accountable_id == params.receiver_id
   1688 		assert to_res.custodian_id == params.receiver_id
   1689 		assert Decimal.eq?(to_res.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value)
   1690 		assert to_res.accounting_quantity_has_unit_id == params.resource_quantity.has_unit_id
   1691 		assert Decimal.eq?(to_res.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value)
   1692 		assert to_res.onhand_quantity_has_unit_id == params.resource_quantity.has_unit_id
   1693 
   1694 		from(r in EconomicResource,
   1695 			where: r.id in ^contained_ids,
   1696 			select: map(r, ~w[primary_accountable_id custodian_id contained_in_id]a))
   1697 		|> Repo.all()
   1698 		|> Enum.each(fn r ->
   1699 			assert r.primary_accountable_id == evt.receiver_id
   1700 			assert r.custodian_id == evt.receiver_id
   1701 			assert r.contained_in_id == to_res.id
   1702 		end)
   1703 	end
   1704 
   1705 	@tag :want_to_resource
   1706 	test "pass with `:to_resource_inventoried_as`", %{params: params} do
   1707 		res_before = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1708 		to_res_before = EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1709 
   1710 		assert {:ok, %EconomicEvent{}} = Domain.create(params)
   1711 		res_after = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1712 		to_res_after = EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1713 
   1714 		assert Decimal.eq?(res_after.accounting_quantity_has_numerical_value,
   1715 			Decimal.sub(res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1716 		assert Decimal.eq?(res_after.onhand_quantity_has_numerical_value,
   1717 			Decimal.sub(res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1718 
   1719 		assert Decimal.eq?(to_res_after.accounting_quantity_has_numerical_value,
   1720 			Decimal.add(to_res_before.accounting_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1721 		assert Decimal.eq?(to_res_after.onhand_quantity_has_numerical_value,
   1722 			Decimal.add(to_res_before.onhand_quantity_has_numerical_value, params.resource_quantity.has_numerical_value))
   1723 	end
   1724 
   1725 	test "fail when provider doesn't have accountability over the resource", %{params: params} do
   1726 		EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1727 		|> Changeset.change(primary_accountable_id: Factory.insert!(:agent).id)
   1728 		|> Repo.update!()
   1729 
   1730 		assert {:error, "you don't have accountability over resource-inventoried-as"} =
   1731 			Domain.create(params)
   1732 	end
   1733 
   1734 	test "fail when provider doesn't have custody over the resource", %{params: params} do
   1735 		EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1736 		|> Changeset.change(custodian_id: Factory.insert!(:agent).id)
   1737 		|> Repo.update!()
   1738 
   1739 		assert {:error, "you don't have custody over resource-inventoried-as"} =
   1740 			Domain.create(params)
   1741 	end
   1742 
   1743 	@tag :want_to_resource
   1744 	test "fail when provider doesn't have accountability over the to-resource", %{params: params} do
   1745 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1746 		|> Changeset.change(primary_accountable_id: Factory.insert!(:agent).id)
   1747 		|> Repo.update!()
   1748 
   1749 		assert {:error, "you don't have accountability over to-resource-inventoried-as"} =
   1750 			Domain.create(params)
   1751 	end
   1752 
   1753 	@tag :want_to_resource
   1754 	test "fail when provider doesn't have custody over the to-resource", %{params: params} do
   1755 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1756 		|> Changeset.change(custodian_id: Factory.insert!(:agent).id)
   1757 		|> Repo.update!()
   1758 
   1759 		assert {:error, "you don't have custody over to-resource-inventoried-as"} =
   1760 			Domain.create(params)
   1761 	end
   1762 
   1763 	@tag :want_contained
   1764 	test "fail when the resource is a contained resource", %{params: params} do
   1765 		assert {:error, "you can't move a contained resource"} =
   1766 			Domain.create(params)
   1767 	end
   1768 
   1769 	test "fail when event's unit and resource's unit differ", %{params: params} do
   1770 		params = update_in(params.resource_quantity.has_unit_id, fn _ -> Factory.insert!(:unit).id end)
   1771 		assert {:error, "the unit of resource-quantity must match with the unit of resource-inventoried-as"} =
   1772 			Domain.create(params)
   1773 	end
   1774 
   1775 	@tag :want_to_resource
   1776 	test "fail when event's unit and to-resource's unit differ", %{params: params} do
   1777 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1778 		|> Changeset.change(accounting_quantity_has_unit_id: Factory.insert!(:unit).id)
   1779 		|> Repo.update!()
   1780 
   1781 		assert {:error, "the unit of resource-quantity must match with the unit of to-resource-inventoried-as"} =
   1782 			Domain.create(params)
   1783 	end
   1784 
   1785 	@tag :want_container
   1786 	test "fail when the resource is a container and accounting-quantity is non-positive", %{params: params} do
   1787 		err = "the move events need container resources to have positive accounting-quantity"
   1788 		res = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1789 
   1790 		Changeset.change(res, accounting_quantity_has_numerical_value: 0.0) |> Repo.update!()
   1791 		assert {:error, ^err} = Domain.create(params)
   1792 
   1793 		Changeset.change(res, accounting_quantity_has_numerical_value: -1.0) |> Repo.update!()
   1794 		assert {:error, ^err} = Domain.create(params)
   1795 	end
   1796 
   1797 	@tag :want_container
   1798 	test "fail when the resource is a container and onhand-quantity is non-positive", %{params: params} do
   1799 		err = "the move events need container resources to have positive onhand-quantity"
   1800 		res = EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1801 
   1802 		Changeset.change(res, onhand_quantity_has_numerical_value: 0.0) |> Repo.update!()
   1803 		assert {:error, ^err} = Domain.create(params)
   1804 
   1805 		Changeset.change(res, onhand_quantity_has_numerical_value: -1.0) |> Repo.update!()
   1806 		assert {:error, ^err} = Domain.create(params)
   1807 	end
   1808 
   1809 	@tag :want_container
   1810 	test "fail when event's quantity value and resource's accounting-quantity value differ", %{params: params} do
   1811 		EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1812 		|> Changeset.change(accounting_quantity_has_numerical_value: Decimal.add(params.resource_quantity.has_numerical_value, 1))
   1813 		|> Repo.update!()
   1814 
   1815 		assert {:error, "the move events need to fully move the resource"} =
   1816 			Domain.create(params)
   1817 	end
   1818 
   1819 	@tag :want_container
   1820 	test "fail when event's quantity value and resource's onhnad-quantity value differ", %{params: params} do
   1821 		EconomicResource.Domain.one!(params.resource_inventoried_as_id)
   1822 		|> Changeset.change(onhand_quantity_has_numerical_value: Decimal.add(params.resource_quantity.has_numerical_value, 1))
   1823 		|> Repo.update!()
   1824 
   1825 		assert {:error, "the move events need to fully move the resource"} =
   1826 			Domain.create(params)
   1827 	end
   1828 
   1829 	@tag :want_container
   1830 	@tag :want_to_resource
   1831 	test "fail when transfering a container resource into another resource", %{params: params} do
   1832 		assert {:error, "you can't move a container resource into another resource"} =
   1833 			Domain.create(params)
   1834 	end
   1835 
   1836 	@tag :want_to_resource
   1837 	test "fail when the to-resource is a contained resource", %{params: params} do
   1838 		agent = Factory.insert!(:agent)
   1839 		raise_params = %{
   1840 			action_id: "raise",
   1841 			provider_id: agent.id,
   1842 			receiver_id: agent.id,
   1843 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
   1844 			resource_quantity: %{
   1845 				has_unit_id: Factory.insert!(:unit).id,
   1846 				has_numerical_value: Factory.decimal(),
   1847 			},
   1848 			has_end: Factory.now(),
   1849 		}
   1850 		assert {:ok, %EconomicEvent{resource_inventoried_as_id: tmp_res_id}} =
   1851 			Domain.create(raise_params, %{name: Factory.str("name")})
   1852 
   1853 		# TODO: use combine-separate when implemented instead
   1854 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1855 		|> Changeset.change(contained_in_id: tmp_res_id)
   1856 		|> Repo.update!()
   1857 
   1858 		assert {:error, "you can't move into a contained resource"} =
   1859 			Domain.create(params)
   1860 	end
   1861 
   1862 	@tag :want_to_resource
   1863 	test "fail when the to-resource is a container resource", %{params: params} do
   1864 		agent = Factory.insert!(:agent)
   1865 		raise_params = %{
   1866 			action_id: "raise",
   1867 			provider_id: agent.id,
   1868 			receiver_id: agent.id,
   1869 			resource_conforms_to_id: Factory.insert!(:resource_specification).id,
   1870 			resource_quantity: %{
   1871 				has_unit_id: Factory.insert!(:unit).id,
   1872 				has_numerical_value: Factory.decimal(),
   1873 			},
   1874 			has_end: Factory.now(),
   1875 		}
   1876 		assert {:ok, %EconomicEvent{} = evt} =
   1877 			Domain.create(raise_params, %{name: Factory.str("name")})
   1878 		evt = Domain.preload(evt, :resource_inventoried_as)
   1879 		tmp_res = evt.resource_inventoried_as
   1880 		# TODO: use combine-separate when implemented instead
   1881 		Changeset.change(tmp_res, contained_in_id: params.to_resource_inventoried_as_id)
   1882 		|> Repo.update!()
   1883 
   1884 		assert {:error, "you can't move into a container resource"} =
   1885 			Domain.create(params)
   1886 	end
   1887 
   1888 	@tag :want_to_resource
   1889 	test "fail when resoure and to-resource don't conform to the same spec", %{params: params} do
   1890 		EconomicResource.Domain.one!(params.to_resource_inventoried_as_id)
   1891 		|> Changeset.change(conforms_to_id: Factory.insert!(:resource_specification).id)
   1892 		|> Repo.update!()
   1893 
   1894 		assert {:error, "the resources must conform to the same specification"} =
   1895 			Domain.create(params)
   1896 	end
   1897 end
   1898 
   1899 describe "update/2" do
   1900 end
   1901 
   1902 describe "preload/2" do
   1903 	# test "preloads :resource_quantity", %{inserted: eco_evt} do
   1904 	# 	eco_evt = Domain.preload(eco_evt, :resource_quantity)
   1905 	# 	assert res_qty = %Measure{} = eco_evt.resource_quantity
   1906 	# 	assert res_qty.has_unit_id == eco_evt.resource_quantity_has_unit_id
   1907 	# 	assert res_qty.has_numerical_value == eco_evt.resource_quantity_has_numerical_value
   1908 	# end
   1909 
   1910 	# test "preloads :effort_quantity", %{inserted: eco_evt} do
   1911 	# 	eco_evt = Domain.preload(eco_evt, :effort_quantity)
   1912 	# 	assert eff_qty = %Measure{} = eco_evt.effort_quantity
   1913 	# 	assert eff_qty.has_unit_id == eco_evt.effort_quantity_has_unit_id
   1914 	# 	assert eff_qty.has_numerical_value == eco_evt.effort_quantity_has_numerical_value
   1915 	# end
   1916 
   1917 	# test "preloads :inserted_resource", %{inserted: eco_evt} do
   1918 	# 	eco_evt = Domain.preload(eco_evt, :inserted_resource)
   1919 	# 	assert eco_evt_res = %RecipeResource{} = eco_evt.inserted_resource
   1920 	# 	assert eco_evt_res.id == eco_evt.inserted_resource_id
   1921 	# end
   1922 
   1923 	# test "preloads :action", %{inserted: eco_evt} do
   1924 	# 	eco_evt = Domain.preload(eco_evt, :action)
   1925 	# 	assert action = %Action{} = eco_evt.action
   1926 	# 	assert action.id == eco_evt.action_id
   1927 	# end
   1928 
   1929 	# test "preloads :recipe_input_of", %{inserted: eco_evt} do
   1930 	# 	eco_evt = Domain.preload(eco_evt, :recipe_input_of)
   1931 	# 	assert rec_in_of = %RecipeProcess{} = eco_evt.recipe_input_of
   1932 	# 	assert rec_in_of.id == eco_evt.recipe_input_of_id
   1933 	# end
   1934 
   1935 	# test "preloads :recipe_output_of", %{inserted: eco_evt} do
   1936 	# 	eco_evt = Domain.preload(eco_evt, :recipe_output_of)
   1937 	# 	assert rec_out_of = %RecipeProcess{} = eco_evt.recipe_output_of
   1938 	# 	assert rec_out_of.id == eco_evt.recipe_output_of_id
   1939 	# end
   1940 
   1941 	# test "preloads :recipe_clause_of", %{inserted: eco_evt} do
   1942 	# 	eco_evt = Domain.preload(eco_evt, :recipe_clause_of)
   1943 	# 	assert rec_clause_of = %RecipeExchange{} = eco_evt.recipe_clause_of
   1944 	# 	assert rec_clause_of.id == eco_evt.recipe_clause_of_id
   1945 	# end
   1946 end
   1947 end