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