hs-office-coopassets, no get API endpoints yet
This commit is contained in:
parent
5ada0dae35
commit
a39cf73cf0
@ -0,0 +1,118 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopassets;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopAssetsApi;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopAssetsTransactionInsertResource;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopAssetsTransactionResource;
|
||||||
|
import net.hostsharing.hsadminng.mapper.Mapper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.ValidationException;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static java.lang.String.join;
|
||||||
|
import static net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopAssetsTransactionTypeResource.*;
|
||||||
|
import static net.hostsharing.hsadminng.mapper.Mapper.map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAssetsApi {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private HsOfficeCoopAssetsTransactionRepository coopAssetsTransactionRepo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public ResponseEntity<List<HsOfficeCoopAssetsTransactionResource>> listCoopAssets(
|
||||||
|
final String currentUser,
|
||||||
|
final String assumedRoles,
|
||||||
|
final UUID membershipUuid,
|
||||||
|
final @DateTimeFormat(iso = ISO.DATE) LocalDate fromValueDate,
|
||||||
|
final @DateTimeFormat(iso = ISO.DATE) LocalDate toValueDate) {
|
||||||
|
context.define(currentUser, assumedRoles);
|
||||||
|
|
||||||
|
final var entities = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
|
membershipUuid,
|
||||||
|
fromValueDate,
|
||||||
|
toValueDate);
|
||||||
|
|
||||||
|
final var resources = Mapper.mapList(entities, HsOfficeCoopAssetsTransactionResource.class);
|
||||||
|
return ResponseEntity.ok(resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public ResponseEntity<HsOfficeCoopAssetsTransactionResource> addCoopAssetsTransaction(
|
||||||
|
final String currentUser,
|
||||||
|
final String assumedRoles,
|
||||||
|
@Valid final HsOfficeCoopAssetsTransactionInsertResource requestBody) {
|
||||||
|
|
||||||
|
context.define(currentUser, assumedRoles);
|
||||||
|
validate(requestBody);
|
||||||
|
|
||||||
|
final var entityToSave = map(requestBody, HsOfficeCoopAssetsTransactionEntity.class);
|
||||||
|
entityToSave.setUuid(UUID.randomUUID());
|
||||||
|
|
||||||
|
final var saved = coopAssetsTransactionRepo.save(entityToSave);
|
||||||
|
|
||||||
|
final var uri =
|
||||||
|
MvcUriComponentsBuilder.fromController(getClass())
|
||||||
|
.path("/api/hs/office/coopassetstransactions/{id}")
|
||||||
|
.buildAndExpand(entityToSave.getUuid())
|
||||||
|
.toUri();
|
||||||
|
final var mapped = map(saved, HsOfficeCoopAssetsTransactionResource.class);
|
||||||
|
return ResponseEntity.created(uri).body(mapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validate(final HsOfficeCoopAssetsTransactionInsertResource requestBody) {
|
||||||
|
final var violations = new ArrayList<String>();
|
||||||
|
validateDebitTransaction(requestBody, violations);
|
||||||
|
validateCreditTransaction(requestBody, violations);
|
||||||
|
validateAssetValue(requestBody, violations);
|
||||||
|
if (violations.size() > 0) {
|
||||||
|
throw new ValidationException("[" + join(", ", violations) + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validateDebitTransaction(
|
||||||
|
final HsOfficeCoopAssetsTransactionInsertResource requestBody,
|
||||||
|
final ArrayList<String> violations) {
|
||||||
|
if (List.of(DEPOSIT, ADOPTION).contains(requestBody.getTransactionType())
|
||||||
|
&& requestBody.getAssetValue().signum() < 0) {
|
||||||
|
violations.add("for %s, assetValue must be positive but is \"%.2f\"".formatted(
|
||||||
|
requestBody.getTransactionType(), requestBody.getAssetValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validateCreditTransaction(
|
||||||
|
final HsOfficeCoopAssetsTransactionInsertResource requestBody,
|
||||||
|
final ArrayList<String> violations) {
|
||||||
|
if (List.of(DISBURSAL, TRANSFER, CLEARING, LOSS).contains(requestBody.getTransactionType())
|
||||||
|
&& requestBody.getAssetValue().signum() > 0) {
|
||||||
|
violations.add("for %s, assetValue must be negative but is \"%.2f\"".formatted(
|
||||||
|
requestBody.getTransactionType(), requestBody.getAssetValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validateAssetValue(
|
||||||
|
final HsOfficeCoopAssetsTransactionInsertResource requestBody,
|
||||||
|
final ArrayList<String> violations) {
|
||||||
|
if (requestBody.getAssetValue().signum() == 0) {
|
||||||
|
violations.add("assetValue must not be 0 but is \"%.2f\"".formatted(
|
||||||
|
requestBody.getAssetValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopassets;
|
||||||
|
|
||||||
|
import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType;
|
||||||
|
import lombok.*;
|
||||||
|
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
|
||||||
|
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||||
|
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||||
|
import org.hibernate.annotations.Type;
|
||||||
|
import org.hibernate.annotations.TypeDef;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "hs_office_coopassetstransaction_rv")
|
||||||
|
@TypeDef(
|
||||||
|
name = "pgsql_enum",
|
||||||
|
typeClass = PostgreSQLEnumType.class
|
||||||
|
)
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@DisplayName("CoopAssetsTransaction")
|
||||||
|
public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable {
|
||||||
|
|
||||||
|
private static Stringify<HsOfficeCoopAssetsTransactionEntity> stringify = stringify(HsOfficeCoopAssetsTransactionEntity.class)
|
||||||
|
.withProp(e -> e.getMembership().getMemberNumber())
|
||||||
|
.withProp(HsOfficeCoopAssetsTransactionEntity::getValueDate)
|
||||||
|
.withProp(HsOfficeCoopAssetsTransactionEntity::getTransactionType)
|
||||||
|
.withProp(HsOfficeCoopAssetsTransactionEntity::getAssetValue)
|
||||||
|
.withProp(HsOfficeCoopAssetsTransactionEntity::getReference)
|
||||||
|
.withSeparator(", ")
|
||||||
|
.quotedValues(false);
|
||||||
|
|
||||||
|
private @Id UUID uuid;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "membershipuuid")
|
||||||
|
private HsOfficeMembershipEntity membership;
|
||||||
|
|
||||||
|
@Column(name = "transactiontype")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@Type( type = "pgsql_enum" )
|
||||||
|
private HsOfficeCoopAssetsTransactionType transactionType;
|
||||||
|
|
||||||
|
@Column(name = "valuedate")
|
||||||
|
private LocalDate valueDate;
|
||||||
|
|
||||||
|
@Column(name = "assetvalue")
|
||||||
|
private BigDecimal assetValue;
|
||||||
|
|
||||||
|
@Column(name = "reference")
|
||||||
|
private String reference;
|
||||||
|
|
||||||
|
@Column(name = "comment")
|
||||||
|
private String comment;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return stringify.apply(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toShortString() {
|
||||||
|
return membership.getMemberNumber() + new DecimalFormat("+0.00").format(assetValue);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopassets;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.office.coopshares.HsOfficeCoopSharesTransactionEntity;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.Repository;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface HsOfficeCoopAssetsTransactionRepository extends Repository<HsOfficeCoopAssetsTransactionEntity, UUID> {
|
||||||
|
|
||||||
|
Optional<HsOfficeCoopAssetsTransactionEntity> findByUuid(UUID id);
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
SELECT at FROM HsOfficeCoopAssetsTransactionEntity at
|
||||||
|
WHERE ( CAST(:membershipUuid AS org.hibernate.type.UUIDCharType) IS NULL OR at.membership.uuid = :membershipUuid)
|
||||||
|
AND ( CAST(:fromValueDate AS java.time.LocalDate) IS NULL OR (at.valueDate >= :fromValueDate))
|
||||||
|
AND ( CAST(:toValueDate AS java.time.LocalDate)IS NULL OR (at.valueDate <= :toValueDate))
|
||||||
|
ORDER BY at.membership.memberNumber, at.valueDate
|
||||||
|
""")
|
||||||
|
List<HsOfficeCoopAssetsTransactionEntity> findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
|
UUID membershipUuid, LocalDate fromValueDate, LocalDate toValueDate);
|
||||||
|
|
||||||
|
HsOfficeCoopAssetsTransactionEntity save(final HsOfficeCoopAssetsTransactionEntity entity);
|
||||||
|
|
||||||
|
long count();
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopassets;
|
||||||
|
|
||||||
|
public enum HsOfficeCoopAssetsTransactionType {
|
||||||
|
ADJUSTMENT, DEPOSIT, DISBURSAL, TRANSFER, ADOPTION, CLEARING, LOSS
|
||||||
|
}
|
@ -12,6 +12,7 @@ map:
|
|||||||
- type: array => java.util.List
|
- type: array => java.util.List
|
||||||
- type: string:uuid => java.util.UUID
|
- type: string:uuid => java.util.UUID
|
||||||
- type: string:format => java.lang.String
|
- type: string:format => java.lang.String
|
||||||
|
- type: number:currency => java.math.BigDecimal
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
/api/hs/office/partners/{partnerUUID}:
|
/api/hs/office/partners/{partnerUUID}:
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
components:
|
||||||
|
|
||||||
|
schemas:
|
||||||
|
|
||||||
|
HsOfficeCoopAssetsTransactionType:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- ADJUSTMENT
|
||||||
|
- DEPOSIT
|
||||||
|
- DISBURSAL
|
||||||
|
- TRANSFER
|
||||||
|
- ADOPTION
|
||||||
|
- CLEARING
|
||||||
|
- LOSS
|
||||||
|
|
||||||
|
HsOfficeCoopAssetsTransaction:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
uuid:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
transactionType:
|
||||||
|
$ref: '#/components/schemas/HsOfficeCoopAssetsTransactionType'
|
||||||
|
assetValue:
|
||||||
|
type: number
|
||||||
|
format: currency
|
||||||
|
valueDate:
|
||||||
|
type: string
|
||||||
|
format: date
|
||||||
|
reference:
|
||||||
|
type: string
|
||||||
|
comment:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
HsOfficeCoopAssetsTransactionInsert:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
membershipUuid:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: false
|
||||||
|
transactionType:
|
||||||
|
$ref: '#/components/schemas/HsOfficeCoopAssetsTransactionType'
|
||||||
|
assetValue:
|
||||||
|
type: number
|
||||||
|
format: currency
|
||||||
|
valueDate:
|
||||||
|
type: string
|
||||||
|
format: date
|
||||||
|
reference:
|
||||||
|
type: string
|
||||||
|
minLength: 6
|
||||||
|
maxLength: 48
|
||||||
|
comment:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- membershipUuid
|
||||||
|
- transactionType
|
||||||
|
- assetValue
|
||||||
|
- valueDate
|
||||||
|
- reference
|
||||||
|
additionalProperties: false
|
@ -0,0 +1,72 @@
|
|||||||
|
get:
|
||||||
|
summary: Returns a list of (optionally filtered) cooperative asset transactions.
|
||||||
|
description: Returns the list of (optionally filtered) cooperative asset transactions which are visible to the current user or any of it's assumed roles.
|
||||||
|
tags:
|
||||||
|
- hs-office-coopAssets
|
||||||
|
operationId: listCoopAssets
|
||||||
|
parameters:
|
||||||
|
- $ref: './auth.yaml#/components/parameters/currentUser'
|
||||||
|
- $ref: './auth.yaml#/components/parameters/assumedRoles'
|
||||||
|
- name: membershipUuid
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: Optional UUID of the related membership.
|
||||||
|
- name: fromValueDate
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: date
|
||||||
|
description: Optional value date range start (inclusive).
|
||||||
|
- name: toValueDate
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: date
|
||||||
|
description: Optional value date range end (inclusive).
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
'application/json':
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: './hs-office-coopassets-schemas.yaml#/components/schemas/HsOfficeCoopAssetsTransaction'
|
||||||
|
"401":
|
||||||
|
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
||||||
|
"403":
|
||||||
|
$ref: './error-responses.yaml#/components/responses/Forbidden'
|
||||||
|
|
||||||
|
post:
|
||||||
|
summary: Adds a new cooperative asset transaction.
|
||||||
|
tags:
|
||||||
|
- hs-office-coopAssets
|
||||||
|
operationId: addCoopAssetsTransaction
|
||||||
|
parameters:
|
||||||
|
- $ref: './auth.yaml#/components/parameters/currentUser'
|
||||||
|
- $ref: './auth.yaml#/components/parameters/assumedRoles'
|
||||||
|
requestBody:
|
||||||
|
description: A JSON object describing the new cooperative assets transaction.
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '/hs-office-coopassets-schemas.yaml#/components/schemas/HsOfficeCoopAssetsTransactionInsert'
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
content:
|
||||||
|
'application/json':
|
||||||
|
schema:
|
||||||
|
$ref: './hs-office-coopassets-schemas.yaml#/components/schemas/HsOfficeCoopAssetsTransaction'
|
||||||
|
"401":
|
||||||
|
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
||||||
|
"403":
|
||||||
|
$ref: './error-responses.yaml#/components/responses/Forbidden'
|
||||||
|
"409":
|
||||||
|
$ref: './error-responses.yaml#/components/responses/Conflict'
|
@ -84,3 +84,9 @@ paths:
|
|||||||
|
|
||||||
/api/hs/office/coopsharestransactions:
|
/api/hs/office/coopsharestransactions:
|
||||||
$ref: "./hs-office-coopshares.yaml"
|
$ref: "./hs-office-coopshares.yaml"
|
||||||
|
|
||||||
|
|
||||||
|
# Coop Assets Transaction
|
||||||
|
|
||||||
|
/api/hs/office/coopassetstransactions:
|
||||||
|
$ref: "./hs-office-coopassets.yaml"
|
||||||
|
62
src/main/resources/db/changelog/320-hs-office-coopassets.sql
Normal file
62
src/main/resources/db/changelog/320-hs-office-coopassets.sql
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
--liquibase formatted sql
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopassets-MAIN-TABLE:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE TYPE HsOfficeCoopAssetsTransactionType AS ENUM ('ADJUSTMENT',
|
||||||
|
'DEPOSIT',
|
||||||
|
'DISBURSAL',
|
||||||
|
'TRANSFER',
|
||||||
|
'ADOPTION',
|
||||||
|
'CLEARING',
|
||||||
|
'LOSS');
|
||||||
|
|
||||||
|
CREATE CAST (character varying as HsOfficeCoopAssetsTransactionType) WITH INOUT AS IMPLICIT;
|
||||||
|
|
||||||
|
create table if not exists hs_office_coopassetstransaction
|
||||||
|
(
|
||||||
|
uuid uuid unique references RbacObject (uuid) initially deferred,
|
||||||
|
membershipUuid uuid not null references hs_office_membership(uuid),
|
||||||
|
transactionType HsOfficeCoopAssetsTransactionType not null,
|
||||||
|
valueDate date not null,
|
||||||
|
assetValue money,
|
||||||
|
reference varchar(48),
|
||||||
|
comment varchar(512)
|
||||||
|
);
|
||||||
|
--//
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopassets-ASSET-VALUE-CONSTRAINT:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
create or replace function checkAssetsByMembershipUuid(forMembershipUuid UUID, newAssetValue money)
|
||||||
|
returns boolean
|
||||||
|
language plpgsql as $$
|
||||||
|
declare
|
||||||
|
currentAssetValue money;
|
||||||
|
totalAssetValue money;
|
||||||
|
begin
|
||||||
|
select sum(cat.assetValue)
|
||||||
|
from hs_office_coopassetstransaction cat
|
||||||
|
where cat.membershipUuid = forMembershipUuid
|
||||||
|
into currentAssetValue;
|
||||||
|
totalAssetValue := currentAssetValue + newAssetValue;
|
||||||
|
if totalAssetValue::numeric < 0 then
|
||||||
|
raise exception '[400] coop assets transaction would result in a negative balance of assets';
|
||||||
|
end if;
|
||||||
|
return true;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
alter table hs_office_coopassetstransaction
|
||||||
|
add constraint hs_office_coopassets_positive
|
||||||
|
check ( checkAssetsByMembershipUuid(membershipUuid, assetValue) );
|
||||||
|
|
||||||
|
--//
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopassets-MAIN-TABLE-JOURNAL:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
call create_journal('hs_office_coopassetstransaction');
|
||||||
|
--//
|
@ -0,0 +1,29 @@
|
|||||||
|
### hs_office_coopAssetsTransaction RBAC
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
|
||||||
|
subgraph hsOfficeMembership
|
||||||
|
direction TB
|
||||||
|
style hsOfficeMembership fill:#eee
|
||||||
|
|
||||||
|
role:hsOfficeMembership.owner[membership.admin]
|
||||||
|
--> role:hsOfficeMembership.admin[membership.admin]
|
||||||
|
--> role:hsOfficeMembership.agent[membership.agent]
|
||||||
|
--> role:hsOfficeMembership.tenant[membership.tenant]
|
||||||
|
--> role:hsOfficeMembership.guest[membership.guest]
|
||||||
|
|
||||||
|
role:hsOfficePartner.agent --> role:hsOfficeMembership.agent
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph hsOfficeCoopAssetsTransaction
|
||||||
|
|
||||||
|
role:hsOfficeMembership.admin
|
||||||
|
--> perm:hsOfficeCoopAssetsTransaction.create{{coopAssetsTx.create}}
|
||||||
|
|
||||||
|
role:hsOfficeMembership.agent
|
||||||
|
--> perm:hsOfficeCoopAssetsTransaction.view{{coopAssetsTx.view}}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
```
|
@ -0,0 +1,124 @@
|
|||||||
|
--liquibase formatted sql
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopAssetsTransaction-rbac-OBJECT:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
call generateRelatedRbacObject('hs_office_coopAssetsTransaction');
|
||||||
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopAssetsTransaction-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
call generateRbacRoleDescriptors('hsOfficeCoopAssetsTransaction', 'hs_office_coopAssetsTransaction');
|
||||||
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopAssetsTransaction-rbac-ROLES-CREATION:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates and updates the permissions for coopAssetsTransaction entities.
|
||||||
|
*/
|
||||||
|
|
||||||
|
create or replace function hsOfficeCoopAssetsTransactionRbacRolesTrigger()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
declare
|
||||||
|
newHsOfficeMembership hs_office_membership;
|
||||||
|
begin
|
||||||
|
|
||||||
|
select * from hs_office_membership as p where p.uuid = NEW.membershipUuid into newHsOfficeMembership;
|
||||||
|
|
||||||
|
if TG_OP = 'INSERT' then
|
||||||
|
|
||||||
|
-- Each coopAssetsTransaction entity belong exactly to one membership entity
|
||||||
|
-- and it makes little sense just to delegate coopAssetsTransaction roles.
|
||||||
|
-- Therefore, we do not create coopAssetsTransaction roles at all,
|
||||||
|
-- but instead just assign extra permissions to existing membership-roles.
|
||||||
|
|
||||||
|
-- coopassetstransactions cannot be edited nor deleted, just created+viewed
|
||||||
|
call grantPermissionsToRole(
|
||||||
|
getRoleId(hsOfficeMembershipTenant(newHsOfficeMembership), 'fail'),
|
||||||
|
createPermissions(NEW.uuid, array ['view'])
|
||||||
|
);
|
||||||
|
|
||||||
|
else
|
||||||
|
raise exception 'invalid usage of TRIGGER';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
/*
|
||||||
|
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
|
||||||
|
*/
|
||||||
|
create trigger createRbacRolesForHsOfficeCoopAssetsTransaction_Trigger
|
||||||
|
after insert
|
||||||
|
on hs_office_coopAssetsTransaction
|
||||||
|
for each row
|
||||||
|
execute procedure hsOfficeCoopAssetsTransactionRbacRolesTrigger();
|
||||||
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopAssetsTransaction-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
call generateRbacIdentityView('hs_office_coopAssetsTransaction',
|
||||||
|
idNameExpression => 'target.reference');
|
||||||
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopAssetsTransaction-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
call generateRbacRestrictedView('hs_office_coopAssetsTransaction', orderby => 'target.reference');
|
||||||
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopAssetsTransaction-rbac-NEW-CoopAssetsTransaction:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
Creates a global permission for new-coopAssetsTransaction and assigns it to the hostsharing admins role.
|
||||||
|
*/
|
||||||
|
do language plpgsql $$
|
||||||
|
declare
|
||||||
|
addCustomerPermissions uuid[];
|
||||||
|
globalObjectUuid uuid;
|
||||||
|
globalAdminRoleUuid uuid ;
|
||||||
|
begin
|
||||||
|
call defineContext('granting global new-coopAssetsTransaction permission to global admin role', null, null, null);
|
||||||
|
|
||||||
|
globalAdminRoleUuid := findRoleId(globalAdmin());
|
||||||
|
globalObjectUuid := (select uuid from global);
|
||||||
|
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-coopassetstransaction']);
|
||||||
|
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
|
||||||
|
*/
|
||||||
|
create or replace function addHsOfficeCoopAssetsTransactionNotAllowedForCurrentSubjects()
|
||||||
|
returns trigger
|
||||||
|
language PLPGSQL
|
||||||
|
as $$
|
||||||
|
begin
|
||||||
|
raise exception '[403] new-coopassetstransaction not permitted for %',
|
||||||
|
array_to_string(currentSubjects(), ';', 'null');
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Checks if the user or assumed roles are allowed to create a new customer.
|
||||||
|
*/
|
||||||
|
create trigger hs_office_coopAssetsTransaction_insert_trigger
|
||||||
|
before insert
|
||||||
|
on hs_office_coopAssetsTransaction
|
||||||
|
for each row
|
||||||
|
when ( not hasAssumedRole() )
|
||||||
|
execute procedure addHsOfficeCoopAssetsTransactionNotAllowedForCurrentSubjects();
|
||||||
|
--//
|
||||||
|
|
@ -0,0 +1,44 @@
|
|||||||
|
--liquibase formatted sql
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopAssetsTransaction-TEST-DATA-GENERATOR:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates a single coopAssetsTransaction test record.
|
||||||
|
*/
|
||||||
|
create or replace procedure createHsOfficeCoopAssetsTransactionTestData(givenMembershipNumber numeric)
|
||||||
|
language plpgsql as $$
|
||||||
|
declare
|
||||||
|
currentTask varchar;
|
||||||
|
membership hs_office_membership;
|
||||||
|
begin
|
||||||
|
currentTask = 'creating coopAssetsTransaction test-data ' || givenMembershipNumber;
|
||||||
|
execute format('set local hsadminng.currentTask to %L', currentTask);
|
||||||
|
|
||||||
|
call defineContext(currentTask);
|
||||||
|
select m.uuid from hs_office_membership m where m.memberNumber = givenMembershipNumber into membership;
|
||||||
|
|
||||||
|
raise notice 'creating test coopAssetsTransaction: %', givenMembershipNumber;
|
||||||
|
insert
|
||||||
|
into hs_office_coopassetstransaction(uuid, membershipuuid, transactiontype, valuedate, assetvalue, reference, comment)
|
||||||
|
values
|
||||||
|
(uuid_generate_v4(), membership.uuid, 'DEPOSIT', '2010-03-15', 320.00, 'ref '||givenMembershipNumber||'-1', 'initial deposit'),
|
||||||
|
(uuid_generate_v4(), membership.uuid, 'DISBURSAL', '2021-09-01', -128.00, 'ref '||givenMembershipNumber||'-2', 'partial disbursal'),
|
||||||
|
(uuid_generate_v4(), membership.uuid, 'ADJUSTMENT', '2022-10-20', 128.00, 'ref '||givenMembershipNumber||'-3', 'some adjustment');
|
||||||
|
end; $$;
|
||||||
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-coopAssetsTransaction-TEST-DATA-GENERATION:1 –context=dev,tc endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
do language plpgsql $$
|
||||||
|
begin
|
||||||
|
call createHsOfficeCoopAssetsTransactionTestData(10001);
|
||||||
|
call createHsOfficeCoopAssetsTransactionTestData(10002);
|
||||||
|
call createHsOfficeCoopAssetsTransactionTestData(10003);
|
||||||
|
end;
|
||||||
|
$$;
|
@ -105,3 +105,9 @@ databaseChangeLog:
|
|||||||
file: db/changelog/313-hs-office-coopshares-rbac.sql
|
file: db/changelog/313-hs-office-coopshares-rbac.sql
|
||||||
- include:
|
- include:
|
||||||
file: db/changelog/318-hs-office-coopshares-test-data.sql
|
file: db/changelog/318-hs-office-coopshares-test-data.sql
|
||||||
|
- include:
|
||||||
|
file: db/changelog/320-hs-office-coopassets.sql
|
||||||
|
- include:
|
||||||
|
file: db/changelog/323-hs-office-coopassets-rbac.sql
|
||||||
|
- include:
|
||||||
|
file: db/changelog/328-hs-office-coopassets-test-data.sql
|
||||||
|
@ -36,6 +36,7 @@ public class ArchitectureTest {
|
|||||||
"..hs.office.relationship",
|
"..hs.office.relationship",
|
||||||
"..hs.office.contact",
|
"..hs.office.contact",
|
||||||
"..hs.office.sepamandate",
|
"..hs.office.sepamandate",
|
||||||
|
"..hs.office.coopassets",
|
||||||
"..hs.office.coopshares",
|
"..hs.office.coopshares",
|
||||||
"..hs.office.membership",
|
"..hs.office.membership",
|
||||||
"..errors",
|
"..errors",
|
||||||
@ -156,7 +157,14 @@ public class ArchitectureTest {
|
|||||||
public static final ArchRule hsOfficeMembershipPackageRule = classes()
|
public static final ArchRule hsOfficeMembershipPackageRule = classes()
|
||||||
.that().resideInAPackage("..hs.office.membership..")
|
.that().resideInAPackage("..hs.office.membership..")
|
||||||
.should().onlyBeAccessed().byClassesThat()
|
.should().onlyBeAccessed().byClassesThat()
|
||||||
.resideInAnyPackage("..hs.office.membership..", "..hs.office.coopshares..");
|
.resideInAnyPackage("..hs.office.membership..", "..hs.office.coopassets..", "..hs.office.coopshares..");
|
||||||
|
|
||||||
|
@ArchTest
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static final ArchRule hsOfficeCoopAssetsPackageRule = classes()
|
||||||
|
.that().resideInAPackage("..hs.office.coopassets..")
|
||||||
|
.should().onlyBeAccessed().byClassesThat()
|
||||||
|
.resideInAnyPackage("..hs.office.coopassets..");
|
||||||
|
|
||||||
@ArchTest
|
@ArchTest
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -0,0 +1,242 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopassets;
|
||||||
|
|
||||||
|
import io.restassured.RestAssured;
|
||||||
|
import io.restassured.http.ContentType;
|
||||||
|
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionRepository;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository;
|
||||||
|
import net.hostsharing.test.Accepts;
|
||||||
|
import net.hostsharing.test.JpaAttempt;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
||||||
|
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
|
|
||||||
|
@SpringBootTest(
|
||||||
|
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||||
|
classes = { HsadminNgApplication.class, JpaAttempt.class }
|
||||||
|
)
|
||||||
|
@Transactional
|
||||||
|
class HsOfficeCoopAssetsTransactionControllerAcceptanceTest {
|
||||||
|
|
||||||
|
@LocalServerPort
|
||||||
|
private Integer port;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HsOfficeMembershipRepository membershipRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
JpaAttempt jpaAttempt;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
EntityManager em;
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@Accepts({ "CoopAssetsTransaction:F(Find)" })
|
||||||
|
class ListCoopAssetsTransactions {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globalAdmin_canViewAllCoopAssetsTransactions() {
|
||||||
|
|
||||||
|
RestAssured // @formatter:off
|
||||||
|
.given()
|
||||||
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
|
.port(port)
|
||||||
|
.when()
|
||||||
|
.get("http://localhost/api/hs/office/coopassetstransactions")
|
||||||
|
.then().log().all().assertThat()
|
||||||
|
.statusCode(200)
|
||||||
|
.contentType("application/json")
|
||||||
|
.body("", hasSize(9)); // @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globalAdmin_canFindCoopAssetsTransactionsByMemberNumber() {
|
||||||
|
|
||||||
|
context.define("superuser-alex@hostsharing.net");
|
||||||
|
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002)
|
||||||
|
.get(0);
|
||||||
|
|
||||||
|
RestAssured // @formatter:off
|
||||||
|
.given()
|
||||||
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
|
.port(port)
|
||||||
|
.when()
|
||||||
|
.get("http://localhost/api/hs/office/coopassetstransactions?membershipUuid="+givenMembership.getUuid())
|
||||||
|
.then().log().all().assertThat()
|
||||||
|
.statusCode(200)
|
||||||
|
.contentType("application/json")
|
||||||
|
.body("", lenientlyEquals("""
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"transactionType": "DEPOSIT",
|
||||||
|
"assetValue": 320.00,
|
||||||
|
"valueDate": "2010-03-15",
|
||||||
|
"reference": "ref 10002-1",
|
||||||
|
"comment": "initial deposit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"transactionType": "DISBURSAL",
|
||||||
|
"assetValue": -128.00,
|
||||||
|
"valueDate": "2021-09-01",
|
||||||
|
"reference": "ref 10002-2",
|
||||||
|
"comment": "partial disbursal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"transactionType": "ADJUSTMENT",
|
||||||
|
"assetValue": 128.00,
|
||||||
|
"valueDate": "2022-10-20",
|
||||||
|
"reference": "ref 10002-3",
|
||||||
|
"comment": "some adjustment"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
""")); // @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globalAdmin_canFindCoopAssetsTransactionsByMemberNumberAndDateRange() {
|
||||||
|
|
||||||
|
context.define("superuser-alex@hostsharing.net");
|
||||||
|
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002)
|
||||||
|
.get(0);
|
||||||
|
|
||||||
|
RestAssured // @formatter:off
|
||||||
|
.given()
|
||||||
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
|
.port(port)
|
||||||
|
.when()
|
||||||
|
.get("http://localhost/api/hs/office/coopassetstransactions?membershipUuid="
|
||||||
|
+ givenMembership.getUuid() + "&fromValueDate=2020-01-01&toValueDate=2021-12-31")
|
||||||
|
.then().log().all().assertThat()
|
||||||
|
.statusCode(200)
|
||||||
|
.contentType("application/json")
|
||||||
|
.body("", lenientlyEquals("""
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"transactionType": "DISBURSAL",
|
||||||
|
"assetValue": -128.00,
|
||||||
|
"valueDate": "2021-09-01",
|
||||||
|
"reference": "ref 10002-2",
|
||||||
|
"comment": "partial disbursal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
""")); // @formatter:on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@Accepts({ "CoopAssetsTransaction:C(Create)" })
|
||||||
|
class AddCoopAssetsTransaction {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globalAdmin_canAddCoopAssetsTransaction() {
|
||||||
|
|
||||||
|
context.define("superuser-alex@hostsharing.net");
|
||||||
|
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001)
|
||||||
|
.get(0);
|
||||||
|
|
||||||
|
final var location = RestAssured // @formatter:off
|
||||||
|
.given()
|
||||||
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("""
|
||||||
|
{
|
||||||
|
"membershipUuid": "%s",
|
||||||
|
"transactionType": "DEPOSIT",
|
||||||
|
"assetValue": 1024.00,
|
||||||
|
"valueDate": "2022-10-13",
|
||||||
|
"reference": "temp ref A",
|
||||||
|
"comment": "just some test coop assets transaction"
|
||||||
|
}
|
||||||
|
""".formatted(givenMembership.getUuid()))
|
||||||
|
.port(port)
|
||||||
|
.when()
|
||||||
|
.post("http://localhost/api/hs/office/coopassetstransactions")
|
||||||
|
.then().log().all().assertThat()
|
||||||
|
.statusCode(201)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("uuid", isUuidValid())
|
||||||
|
.body("", lenientlyEquals("""
|
||||||
|
{
|
||||||
|
"transactionType": "DEPOSIT",
|
||||||
|
"assetValue": 1024.00,
|
||||||
|
"valueDate": "2022-10-13",
|
||||||
|
"reference": "temp ref A",
|
||||||
|
"comment": "just some test coop assets transaction"
|
||||||
|
}
|
||||||
|
"""))
|
||||||
|
.header("Location", startsWith("http://localhost"))
|
||||||
|
.extract().header("Location"); // @formatter:on
|
||||||
|
|
||||||
|
// finally, the new coopAssetsTransaction can be accessed under the generated UUID
|
||||||
|
final var newUserUuid = UUID.fromString(
|
||||||
|
location.substring(location.lastIndexOf('/') + 1));
|
||||||
|
assertThat(newUserUuid).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globalAdmin_canNotCancelMoreAssetsThanCurrentlySubscribed() {
|
||||||
|
|
||||||
|
context.define("superuser-alex@hostsharing.net");
|
||||||
|
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001)
|
||||||
|
.get(0);
|
||||||
|
|
||||||
|
final var location = RestAssured // @formatter:off
|
||||||
|
.given()
|
||||||
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("""
|
||||||
|
{
|
||||||
|
"membershipUuid": "%s",
|
||||||
|
"transactionType": "DISBURSAL",
|
||||||
|
"assetValue": -10240.00,
|
||||||
|
"valueDate": "2022-10-13",
|
||||||
|
"reference": "temp ref X",
|
||||||
|
"comment": "just some test coop assets transaction"
|
||||||
|
}
|
||||||
|
""".formatted(givenMembership.getUuid()))
|
||||||
|
.port(port)
|
||||||
|
.when()
|
||||||
|
.post("http://localhost/api/hs/office/coopassetstransactions")
|
||||||
|
.then().log().all().assertThat()
|
||||||
|
.statusCode(400)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("", lenientlyEquals("""
|
||||||
|
{
|
||||||
|
"status": 400,
|
||||||
|
"error": "Bad Request",
|
||||||
|
"message": "ERROR: [400] coop assets transaction would result in a negative balance of assets"
|
||||||
|
}
|
||||||
|
""")); // @formatter:on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
@AfterEach
|
||||||
|
void cleanup() {
|
||||||
|
jpaAttempt.transacted(() -> {
|
||||||
|
context.define("superuser-alex@hostsharing.net", null);
|
||||||
|
// HsOfficeCoopAssetsTransactionEntity respectively hs_office_coopassetstransaction_rv
|
||||||
|
// cannot be deleted at all, but the underlying table record can be deleted.
|
||||||
|
em.createNativeQuery("delete from hs_office_coopassetstransaction where reference like 'temp %'")
|
||||||
|
.executeUpdate();
|
||||||
|
}).assertSuccessful();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopassets;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import net.hostsharing.test.JsonBuilder;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.EnumSource;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static net.hostsharing.test.JsonBuilder.jsonObject;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
@WebMvcTest(HsOfficeCoopAssetsTransactionController.class)
|
||||||
|
class HsOfficeCoopAssetsTransactionControllerRestTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MockMvc mockMvc;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
Context contextMock;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
HsOfficeCoopAssetsTransactionRepository coopAssetsTransactionRepo;
|
||||||
|
|
||||||
|
static final String VALID_INSERT_REQUEST_BODY = """
|
||||||
|
{
|
||||||
|
"membershipUuid": "%s",
|
||||||
|
"transactionType": "DEPOSIT",
|
||||||
|
"assetValue": 128.00,
|
||||||
|
"valueDate": "2022-10-13",
|
||||||
|
"reference": "valid reference",
|
||||||
|
"comment": "valid comment"
|
||||||
|
}
|
||||||
|
""".formatted(UUID.randomUUID());
|
||||||
|
|
||||||
|
enum BadRequestTestCases {
|
||||||
|
MEMBERSHIP_UUID_MISSING(
|
||||||
|
requestBody -> requestBody.without("membershipUuid"),
|
||||||
|
"[membershipUuid must not be null but is \"null\"]"),
|
||||||
|
|
||||||
|
TRANSACTION_TYPE_MISSING(
|
||||||
|
requestBody -> requestBody.without("transactionType"),
|
||||||
|
"[transactionType must not be null but is \"null\"]"),
|
||||||
|
|
||||||
|
VALUE_DATE_MISSING(
|
||||||
|
requestBody -> requestBody.without("valueDate"),
|
||||||
|
"[valueDate must not be null but is \"null\"]"),
|
||||||
|
|
||||||
|
ASSETS_VALUE_FOR_DEPOSIT_MUST_BE_POSITIVE(
|
||||||
|
requestBody -> requestBody
|
||||||
|
.with("transactionType", "DEPOSIT")
|
||||||
|
.with("assetValue", -64.00),
|
||||||
|
"[for DEPOSIT, assetValue must be positive but is \"-64.00\"]"),
|
||||||
|
|
||||||
|
//TODO: other transaction types
|
||||||
|
|
||||||
|
ASSETS_VALUE_FOR_DISBURSAL_MUST_BE_NEGATIVE(
|
||||||
|
requestBody -> requestBody
|
||||||
|
.with("transactionType", "DISBURSAL")
|
||||||
|
.with("assetValue", 64.00),
|
||||||
|
"[for DISBURSAL, assetValue must be negative but is \"64.00\"]"),
|
||||||
|
|
||||||
|
//TODO: other transaction types
|
||||||
|
|
||||||
|
ASSETS_VALUE_MUST_NOT_BE_NULL(
|
||||||
|
requestBody -> requestBody
|
||||||
|
.with("transactionType", "ADJUSTMENT")
|
||||||
|
.with("assetValue", 0.00),
|
||||||
|
"[assetValue must not be 0 but is \"0.00\"]"),
|
||||||
|
|
||||||
|
REFERENCE_MISSING(
|
||||||
|
requestBody -> requestBody.without("reference"),
|
||||||
|
"[reference must not be null but is \"null\"]"),
|
||||||
|
|
||||||
|
REFERENCE_TOO_SHORT(
|
||||||
|
requestBody -> requestBody.with("reference", "12345"),
|
||||||
|
"[reference size must be between 6 and 48 but is \"12345\"]"),
|
||||||
|
|
||||||
|
REFERENCE_TOO_LONG(
|
||||||
|
requestBody -> requestBody.with("reference", "0123456789012345678901234567890123456789012345678"),
|
||||||
|
"[reference size must be between 6 and 48 but is \"0123456789012345678901234567890123456789012345678\"]");
|
||||||
|
|
||||||
|
private final Function<JsonBuilder, JsonBuilder> givenBodyTransformation;
|
||||||
|
private final String expectedErrorMessage;
|
||||||
|
|
||||||
|
BadRequestTestCases(
|
||||||
|
final Function<JsonBuilder, JsonBuilder> givenBodyTransformation,
|
||||||
|
final String expectedErrorMessage) {
|
||||||
|
this.givenBodyTransformation = givenBodyTransformation;
|
||||||
|
this.expectedErrorMessage = expectedErrorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
String givenRequestBody() {
|
||||||
|
return givenBodyTransformation.apply(jsonObject(VALID_INSERT_REQUEST_BODY)).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@EnumSource(BadRequestTestCases.class)
|
||||||
|
void respondWithBadRequest(final BadRequestTestCases testCase) throws Exception {
|
||||||
|
|
||||||
|
// when
|
||||||
|
mockMvc.perform(MockMvcRequestBuilders
|
||||||
|
.post("/api/hs/office/coopassetstransactions")
|
||||||
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(testCase.givenRequestBody())
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
|
||||||
|
// then
|
||||||
|
.andExpect(status().is4xxClientError())
|
||||||
|
.andExpect(jsonPath("status", is(400)))
|
||||||
|
.andExpect(jsonPath("error", is("Bad Request")))
|
||||||
|
.andExpect(jsonPath("message", is(testCase.expectedErrorMessage)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopassets;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.office.membership.TestHsMembership.testMembership;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class HsOfficeCoopAssetsTransactionEntityTest {
|
||||||
|
|
||||||
|
final HsOfficeCoopAssetsTransactionEntity givenCoopAssetTransaction = HsOfficeCoopAssetsTransactionEntity.builder()
|
||||||
|
.membership(testMembership)
|
||||||
|
.reference("some-ref")
|
||||||
|
.valueDate(LocalDate.parse("2020-01-01"))
|
||||||
|
.transactionType(HsOfficeCoopAssetsTransactionType.DEPOSIT)
|
||||||
|
.assetValue(new BigDecimal("128.00"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toStringContainsAlmostAllPropertiesAccount() {
|
||||||
|
final var result = givenCoopAssetTransaction.toString();
|
||||||
|
|
||||||
|
assertThat(result).isEqualTo("CoopAssetsTransaction(300001, 2020-01-01, DEPOSIT, 128.00, some-ref)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toShortStringContainsOnlyMemberNumberAndSharesCountOnly() {
|
||||||
|
final var result = givenCoopAssetTransaction.toShortString();
|
||||||
|
|
||||||
|
assertThat(result).isEqualTo("300001+128.00");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,269 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopassets;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import net.hostsharing.hsadminng.context.ContextBasedTest;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository;
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository;
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository;
|
||||||
|
import net.hostsharing.test.Array;
|
||||||
|
import net.hostsharing.test.JpaAttempt;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantDisplaysOf;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf;
|
||||||
|
import static net.hostsharing.test.JpaAttempt.attempt;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@DataJpaTest
|
||||||
|
@ComponentScan(basePackageClasses = { HsOfficeCoopAssetsTransactionRepository.class, Context.class, JpaAttempt.class })
|
||||||
|
@DirtiesContext
|
||||||
|
class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBasedTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HsOfficeCoopAssetsTransactionRepository coopAssetsTransactionRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HsOfficeMembershipRepository membershipRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
RawRbacRoleRepository rawRoleRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
RawRbacGrantRepository rawGrantRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
EntityManager em;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
JpaAttempt jpaAttempt;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
HttpServletRequest request;
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class CreateCoopAssetsTransaction {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void globalAdmin_canCreateNewCoopAssetTransaction() {
|
||||||
|
// given
|
||||||
|
context("superuser-alex@hostsharing.net");
|
||||||
|
final var count = coopAssetsTransactionRepo.count();
|
||||||
|
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001)
|
||||||
|
.get(0);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var result = attempt(em, () -> {
|
||||||
|
final var newCoopAssetsTransaction = HsOfficeCoopAssetsTransactionEntity.builder()
|
||||||
|
.uuid(UUID.randomUUID())
|
||||||
|
.membership(givenMembership)
|
||||||
|
.transactionType(HsOfficeCoopAssetsTransactionType.DEPOSIT)
|
||||||
|
.assetValue(new BigDecimal("128.00"))
|
||||||
|
.valueDate(LocalDate.parse("2022-10-18"))
|
||||||
|
.reference("temp ref A")
|
||||||
|
.build();
|
||||||
|
return coopAssetsTransactionRepo.save(newCoopAssetsTransaction);
|
||||||
|
});
|
||||||
|
|
||||||
|
// then
|
||||||
|
result.assertSuccessful();
|
||||||
|
assertThat(result.returnedValue()).isNotNull().extracting(HsOfficeCoopAssetsTransactionEntity::getUuid).isNotNull();
|
||||||
|
assertThatCoopAssetsTransactionIsPersisted(result.returnedValue());
|
||||||
|
assertThat(coopAssetsTransactionRepo.count()).isEqualTo(count + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createsAndGrantsRoles() {
|
||||||
|
// given
|
||||||
|
context("superuser-alex@hostsharing.net");
|
||||||
|
final var initialRoleNames = roleNamesOf(rawRoleRepo.findAll());
|
||||||
|
final var initialGrantNames = grantDisplaysOf(rawGrantRepo.findAll()).stream()
|
||||||
|
.map(s -> s.replace("FirstGmbH-firstcontact", "..."))
|
||||||
|
.map(s -> s.replace("hs_office_", ""))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// when
|
||||||
|
attempt(em, () -> {
|
||||||
|
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(
|
||||||
|
null,
|
||||||
|
10001).get(0);
|
||||||
|
final var newCoopAssetsTransaction = HsOfficeCoopAssetsTransactionEntity.builder()
|
||||||
|
.uuid(UUID.randomUUID())
|
||||||
|
.membership(givenMembership)
|
||||||
|
.transactionType(HsOfficeCoopAssetsTransactionType.DEPOSIT)
|
||||||
|
.assetValue(new BigDecimal("128.00"))
|
||||||
|
.valueDate(LocalDate.parse("2022-10-18"))
|
||||||
|
.reference("temp ref B")
|
||||||
|
.build();
|
||||||
|
return coopAssetsTransactionRepo.save(newCoopAssetsTransaction);
|
||||||
|
});
|
||||||
|
|
||||||
|
// then
|
||||||
|
final var all = rawRoleRepo.findAll();
|
||||||
|
assertThat(roleNamesOf(all)).containsExactlyInAnyOrder(Array.from(initialRoleNames)); // no new roles created
|
||||||
|
assertThat(grantDisplaysOf(rawGrantRepo.findAll()))
|
||||||
|
.map(s -> s.replace("FirstGmbH-firstcontact", "..."))
|
||||||
|
.map(s -> s.replace("hs_office_", ""))
|
||||||
|
.containsExactlyInAnyOrder(Array.fromFormatted(
|
||||||
|
initialGrantNames,
|
||||||
|
"{ grant perm view on coopassetstransaction#temprefB to role membership#10001....tenant by system and assume }",
|
||||||
|
null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertThatCoopAssetsTransactionIsPersisted(final HsOfficeCoopAssetsTransactionEntity saved) {
|
||||||
|
final var found = coopAssetsTransactionRepo.findByUuid(saved.getUuid());
|
||||||
|
assertThat(found).isNotEmpty().get().usingRecursiveComparison().isEqualTo(saved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class FindAllCoopAssetsTransactions {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void globalAdmin_anViewAllCoopAssetsTransactions() {
|
||||||
|
// given
|
||||||
|
context("superuser-alex@hostsharing.net");
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
// then
|
||||||
|
allTheseCoopAssetsTransactionsAreReturned(
|
||||||
|
result,
|
||||||
|
"CoopAssetsTransaction(10001, 2010-03-15, DEPOSIT, 320.00, ref 10001-1)",
|
||||||
|
"CoopAssetsTransaction(10001, 2021-09-01, DISBURSAL, -128.00, ref 10001-2)",
|
||||||
|
"CoopAssetsTransaction(10001, 2022-10-20, ADJUSTMENT, 128.00, ref 10001-3)",
|
||||||
|
|
||||||
|
"CoopAssetsTransaction(10002, 2010-03-15, DEPOSIT, 320.00, ref 10002-1)",
|
||||||
|
"CoopAssetsTransaction(10002, 2021-09-01, DISBURSAL, -128.00, ref 10002-2)",
|
||||||
|
"CoopAssetsTransaction(10002, 2022-10-20, ADJUSTMENT, 128.00, ref 10002-3)",
|
||||||
|
|
||||||
|
"CoopAssetsTransaction(10003, 2010-03-15, DEPOSIT, 320.00, ref 10003-1)",
|
||||||
|
"CoopAssetsTransaction(10003, 2021-09-01, DISBURSAL, -128.00, ref 10003-2)",
|
||||||
|
"CoopAssetsTransaction(10003, 2022-10-20, ADJUSTMENT, 128.00, ref 10003-3)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void globalAdmin_canViewCoopAssetsTransactions_filteredByMembershipUuid() {
|
||||||
|
// given
|
||||||
|
context("superuser-alex@hostsharing.net");
|
||||||
|
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002)
|
||||||
|
.get(0);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
|
givenMembership.getUuid(),
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
// then
|
||||||
|
allTheseCoopAssetsTransactionsAreReturned(
|
||||||
|
result,
|
||||||
|
"CoopAssetsTransaction(10002, 2010-03-15, DEPOSIT, 320.00, ref 10002-1)",
|
||||||
|
"CoopAssetsTransaction(10002, 2021-09-01, DISBURSAL, -128.00, ref 10002-2)",
|
||||||
|
"CoopAssetsTransaction(10002, 2022-10-20, ADJUSTMENT, 128.00, ref 10002-3)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void globalAdmin_canViewCoopAssetsTransactions_filteredByMembershipUuidAndValueDateRange() {
|
||||||
|
// given
|
||||||
|
context("superuser-alex@hostsharing.net");
|
||||||
|
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002)
|
||||||
|
.get(0);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
|
givenMembership.getUuid(),
|
||||||
|
LocalDate.parse("2021-09-01"),
|
||||||
|
LocalDate.parse("2021-09-01"));
|
||||||
|
|
||||||
|
// then
|
||||||
|
allTheseCoopAssetsTransactionsAreReturned(
|
||||||
|
result,
|
||||||
|
"CoopAssetsTransaction(10002, 2021-09-01, DISBURSAL, -128.00, ref 10002-2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void normalUser_canViewOnlyRelatedCoopAssetsTransactions() {
|
||||||
|
// given:
|
||||||
|
context("superuser-alex@hostsharing.net", "hs_office_partner#FirstGmbH-firstcontact.admin");
|
||||||
|
// "hs_office_person#FirstGmbH.admin",
|
||||||
|
|
||||||
|
// when:
|
||||||
|
final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
// then:
|
||||||
|
exactlyTheseCoopAssetsTransactionsAreReturned(
|
||||||
|
result,
|
||||||
|
"CoopAssetsTransaction(10001, 2010-03-15, DEPOSIT, 320.00, ref 10001-1)",
|
||||||
|
"CoopAssetsTransaction(10001, 2021-09-01, DISBURSAL, -128.00, ref 10001-2)",
|
||||||
|
"CoopAssetsTransaction(10001, 2022-10-20, ADJUSTMENT, 128.00, ref 10001-3)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void auditJournalLogIsAvailable() {
|
||||||
|
// given
|
||||||
|
final var query = em.createNativeQuery("""
|
||||||
|
select c.currenttask, j.targettable, j.targetop
|
||||||
|
from tx_journal j
|
||||||
|
join tx_context c on j.contextId = c.contextId
|
||||||
|
where targettable = 'hs_office_coopassetstransaction';
|
||||||
|
""");
|
||||||
|
|
||||||
|
// when
|
||||||
|
@SuppressWarnings("unchecked") final List<Object[]> customerLogEntries = query.getResultList();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(customerLogEntries).map(Arrays::toString).contains(
|
||||||
|
"[creating coopAssetsTransaction test-data 10001, hs_office_coopassetstransaction, INSERT]",
|
||||||
|
"[creating coopAssetsTransaction test-data 10002, hs_office_coopassetstransaction, INSERT]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
@AfterEach
|
||||||
|
void cleanup() {
|
||||||
|
jpaAttempt.transacted(() -> {
|
||||||
|
context("superuser-alex@hostsharing.net", null);
|
||||||
|
em.createQuery("DELETE FROM HsOfficeCoopAssetsTransactionEntity WHERE reference like 'temp ref%'");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void exactlyTheseCoopAssetsTransactionsAreReturned(
|
||||||
|
final List<HsOfficeCoopAssetsTransactionEntity> actualResult,
|
||||||
|
final String... coopAssetsTransactionNames) {
|
||||||
|
assertThat(actualResult)
|
||||||
|
.extracting(coopAssetsTransactionEntity -> coopAssetsTransactionEntity.toString())
|
||||||
|
.containsExactlyInAnyOrder(coopAssetsTransactionNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
void allTheseCoopAssetsTransactionsAreReturned(
|
||||||
|
final List<HsOfficeCoopAssetsTransactionEntity> actualResult,
|
||||||
|
final String... coopAssetsTransactionNames) {
|
||||||
|
assertThat(actualResult)
|
||||||
|
.extracting(coopAssetsTransactionEntity -> coopAssetsTransactionEntity.toString())
|
||||||
|
.contains(coopAssetsTransactionNames);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user