1
0

OfficeScenarioTests CoopShares+Assets (#121)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/121
Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
Michael Hoennig
2024-11-15 11:54:18 +01:00
parent 8f410198e9
commit c98a5acb38
56 changed files with 836 additions and 247 deletions

View File

@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.config;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.openapitools.jackson.nullable.JsonNullableModule;
@ -9,15 +10,20 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@Configuration
public class JsonObjectMapperConfiguration {
@Bean
@Primary
public Jackson2ObjectMapperBuilder customObjectMapper() {
// HOWTO: add JSON converters and specify other JSON mapping configurations
return new Jackson2ObjectMapperBuilder()
.modules(new JsonNullableModule(), new JavaTimeModule())
.featuresToEnable(JsonParser.Feature.ALLOW_COMMENTS, JsonParser.Feature.ALLOW_COMMENTS)
.featuresToEnable(
JsonParser.Feature.ALLOW_COMMENTS,
DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS
)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
}

View File

@ -46,6 +46,7 @@ public class CustomErrorResponse {
this.path = path;
this.statusCode = status.value();
this.statusPhrase = status.getReasonPhrase();
// HOWTO: debug serverside error response - set a breakpoint here
this.message = message.startsWith("ERROR: [") ? message : "ERROR: [" + statusCode + "] " + message;
}
}

View File

@ -36,7 +36,7 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse
@Override
@Transactional(readOnly = true)
public ResponseEntity<List<HsOfficeCoopAssetsTransactionResource>> listCoopAssets(
public ResponseEntity<List<HsOfficeCoopAssetsTransactionResource>> getListOfCoopAssets(
final String currentSubject,
final String assumedRoles,
final UUID membershipUuid,
@ -55,7 +55,7 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse
@Override
@Transactional
public ResponseEntity<HsOfficeCoopAssetsTransactionResource> addCoopAssetsTransaction(
public ResponseEntity<HsOfficeCoopAssetsTransactionResource> postNewCoopAssetTransaction(
final String currentSubject,
final String assumedRoles,
final HsOfficeCoopAssetsTransactionInsertResource requestBody) {
@ -77,7 +77,7 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse
@Override
@Transactional(readOnly = true)
public ResponseEntity<HsOfficeCoopAssetsTransactionResource> getCoopAssetTransactionByUuid(
public ResponseEntity<HsOfficeCoopAssetsTransactionResource> getSingleCoopAssetTransactionByUuid(
final String currentSubject, final String assumedRoles, final UUID assetTransactionUuid) {
context.define(currentSubject, assumedRoles);
@ -128,9 +128,9 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse
}
final BiConsumer<HsOfficeCoopAssetsTransactionInsertResource, HsOfficeCoopAssetsTransactionEntity> RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
if ( resource.getReverseEntryUuid() != null ) {
entity.setAdjustedAssetTx(coopAssetsTransactionRepo.findByUuid(resource.getReverseEntryUuid())
.orElseThrow(() -> new EntityNotFoundException("ERROR: [400] reverseEntityUuid %s not found".formatted(resource.getReverseEntryUuid()))));
if ( resource.getRevertedAssetTxUuid() != null ) {
entity.setRevertedAssetTx(coopAssetsTransactionRepo.findByUuid(resource.getRevertedAssetTxUuid())
.orElseThrow(() -> new EntityNotFoundException("ERROR: [400] reverseEntityUuid %s not found".formatted(resource.getRevertedAssetTxUuid()))));
}
};
};

View File

@ -50,8 +50,8 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, BaseE
.withProp(HsOfficeCoopAssetsTransactionEntity::getAssetValue)
.withProp(HsOfficeCoopAssetsTransactionEntity::getReference)
.withProp(HsOfficeCoopAssetsTransactionEntity::getComment)
.withProp(at -> ofNullable(at.getAdjustedAssetTx()).map(HsOfficeCoopAssetsTransactionEntity::toShortString).orElse(null))
.withProp(at -> ofNullable(at.getAdjustmentAssetTx()).map(HsOfficeCoopAssetsTransactionEntity::toShortString).orElse(null))
.withProp(at -> ofNullable(at.getRevertedAssetTx()).map(HsOfficeCoopAssetsTransactionEntity::toShortString).orElse(null))
.withProp(at -> ofNullable(at.getReversalAssetTx()).map(HsOfficeCoopAssetsTransactionEntity::toShortString).orElse(null))
.quotedValues(false);
@Id
@ -77,7 +77,7 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, BaseE
* The signed value which directly affects the booking balance.
*
* <p>This means, that a DEPOSIT is always positive, a DISBURSAL is always negative,
* but an ADJUSTMENT can bei either positive or negative.
* but an REVERSAL can bei either positive or negative.
* See {@link HsOfficeCoopAssetsTransactionType} for</p> more information.
*/
@Column(name = "assetvalue")
@ -96,14 +96,14 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, BaseE
private String comment;
/**
* Optionally, the UUID of the corresponding transaction for an adjustment transaction.
* Optionally, the UUID of the corresponding transaction for an reversal transaction.
*/
@OneToOne
@JoinColumn(name = "adjustedassettxuuid")
private HsOfficeCoopAssetsTransactionEntity adjustedAssetTx;
@JoinColumn(name = "revertedassettxuuid")
private HsOfficeCoopAssetsTransactionEntity revertedAssetTx;
@OneToOne(mappedBy = "adjustedAssetTx")
private HsOfficeCoopAssetsTransactionEntity adjustmentAssetTx;
@OneToOne(mappedBy = "revertedAssetTx")
private HsOfficeCoopAssetsTransactionEntity reversalAssetTx;
@Override
public HsOfficeCoopAssetsTransactionEntity load() {

View File

@ -4,7 +4,7 @@ public enum HsOfficeCoopAssetsTransactionType {
/**
* correction of wrong bookings, value can be positive or negative
*/
ADJUSTMENT,
REVERSAL,
/**
* payment received from member after signing shares, value >0

View File

@ -38,7 +38,7 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar
@Override
@Transactional(readOnly = true)
public ResponseEntity<List<HsOfficeCoopSharesTransactionResource>> listCoopShares(
public ResponseEntity<List<HsOfficeCoopSharesTransactionResource>> getListOfCoopShares(
final String currentSubject,
final String assumedRoles,
final UUID membershipUuid,
@ -57,7 +57,7 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar
@Override
@Transactional
public ResponseEntity<HsOfficeCoopSharesTransactionResource> addCoopSharesTransaction(
public ResponseEntity<HsOfficeCoopSharesTransactionResource> postNewCoopSharesTransaction(
final String currentSubject,
final String assumedRoles,
final HsOfficeCoopSharesTransactionInsertResource requestBody) {
@ -80,7 +80,7 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar
@Override
@Transactional(readOnly = true)
public ResponseEntity<HsOfficeCoopSharesTransactionResource> getCoopShareTransactionByUuid(
public ResponseEntity<HsOfficeCoopSharesTransactionResource> getSingleCoopShareTransactionByUuid(
final String currentSubject, final String assumedRoles, final UUID shareTransactionUuid) {
context.define(currentSubject, assumedRoles);
@ -131,9 +131,9 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar
}
final BiConsumer<HsOfficeCoopSharesTransactionInsertResource, HsOfficeCoopSharesTransactionEntity> RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
if ( resource.getAdjustedShareTxUuid() != null ) {
entity.setAdjustedShareTx(coopSharesTransactionRepo.findByUuid(resource.getAdjustedShareTxUuid())
.orElseThrow(() -> new EntityNotFoundException("ERROR: [400] adjustedShareTxUuid %s not found".formatted(resource.getAdjustedShareTxUuid()))));
if ( resource.getRevertedShareTxUuid() != null ) {
entity.setRevertedShareTx(coopSharesTransactionRepo.findByUuid(resource.getRevertedShareTxUuid())
.orElseThrow(() -> new EntityNotFoundException("ERROR: [400] revertedShareTxUuid %s not found".formatted(resource.getRevertedShareTxUuid()))));
}
};
}

View File

@ -48,8 +48,8 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, BaseE
.withProp(HsOfficeCoopSharesTransactionEntity::getShareCount)
.withProp(HsOfficeCoopSharesTransactionEntity::getReference)
.withProp(HsOfficeCoopSharesTransactionEntity::getComment)
.withProp(at -> ofNullable(at.getAdjustedShareTx()).map(HsOfficeCoopSharesTransactionEntity::toShortString).orElse(null))
.withProp(at -> ofNullable(at.getAdjustmentShareTx()).map(HsOfficeCoopSharesTransactionEntity::toShortString).orElse(null))
.withProp(at -> ofNullable(at.getRevertedShareTx()).map(HsOfficeCoopSharesTransactionEntity::toShortString).orElse(null))
.withProp(at -> ofNullable(at.getReversalShareTx()).map(HsOfficeCoopSharesTransactionEntity::toShortString).orElse(null))
.quotedValues(false);
@Id
@ -71,7 +71,7 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, BaseE
* The signed value which directly affects the booking balance.
*
* <p>This means, that a SUBSCRIPTION is always positive, a CANCELLATION is always negative,
* but an ADJUSTMENT can bei either positive or negative.
* but an REVERSAL can bei either positive or negative.
* See {@link HsOfficeCoopSharesTransactionType} for</p> more information.
*/
@Column(name = "valuedate")
@ -93,14 +93,14 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, BaseE
private String comment;
/**
* Optionally, the UUID of the corresponding transaction for an adjustment transaction.
* Optionally, the UUID of the corresponding transaction for a REVERSAL transaction.
*/
@OneToOne
@JoinColumn(name = "adjustedsharetxuuid")
private HsOfficeCoopSharesTransactionEntity adjustedShareTx;
@JoinColumn(name = "revertedsharetxuuid")
private HsOfficeCoopSharesTransactionEntity revertedShareTx;
@OneToOne(mappedBy = "adjustedShareTx")
private HsOfficeCoopSharesTransactionEntity adjustmentShareTx;
@OneToOne(mappedBy = "revertedShareTx")
private HsOfficeCoopSharesTransactionEntity reversalShareTx;
@Override
public HsOfficeCoopSharesTransactionEntity load() {

View File

@ -2,9 +2,9 @@ package net.hostsharing.hsadminng.hs.office.coopshares;
public enum HsOfficeCoopSharesTransactionType {
/**
* correction of wrong bookings, with either positive or negative value
* reversal of wrong bookings, with either positive or negative value identical to reversed transaction
*/
ADJUSTMENT,
REVERSAL,
/**
* shares signed, e.g. with the declaration of accession, value >0

View File

@ -16,6 +16,8 @@ import java.util.List;
import java.util.UUID;
import java.util.function.BiConsumer;
import static java.util.Optional.ofNullable;
@RestController
public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
@ -39,7 +41,7 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
context.define(currentSubject, assumedRoles);
final var entities = ( memberNumber != null)
? List.of(membershipRepo.findMembershipByMemberNumber(memberNumber))
? ofNullable(membershipRepo.findMembershipByMemberNumber(memberNumber)).stream().toList()
: membershipRepo.findMembershipsByOptionalPartnerUuid(partnerUuid);
final var resources = mapper.mapList(entities, HsOfficeMembershipResource.class,

View File

@ -14,14 +14,16 @@ public interface HsOfficeMembershipRepository extends Repository<HsOfficeMembers
HsOfficeMembershipEntity save(final HsOfficeMembershipEntity entity);
List<HsOfficeMembershipEntity> findAll();
@Query("""
SELECT membership FROM HsOfficeMembershipEntity membership
WHERE ( CAST(:partnerUuid as org.hibernate.type.UUIDCharType) IS NULL
OR membership.partner.uuid = :partnerUuid )
ORDER BY membership.partner.partnerNumber, membership.memberNumberSuffix
""")
""")
List<HsOfficeMembershipEntity> findMembershipsByOptionalPartnerUuid(UUID partnerUuid);
@Query("""
SELECT membership FROM HsOfficeMembershipEntity membership
WHERE (:partnerNumber = membership.partner.partnerNumber)
@ -31,10 +33,12 @@ public interface HsOfficeMembershipRepository extends Repository<HsOfficeMembers
HsOfficeMembershipEntity findMembershipByPartnerNumberAndSuffix(
@NotNull Integer partnerNumber,
@NotNull String suffix);
default HsOfficeMembershipEntity findMembershipByMemberNumber(Integer memberNumber) {
final var partnerNumber = memberNumber / 100;
final var suffix = memberNumber % 100;
return findMembershipByPartnerNumberAndSuffix(partnerNumber, String.format("%02d", suffix));
final String suffix = String.format("%02d", memberNumber % 100);
final var result = findMembershipByPartnerNumberAndSuffix(partnerNumber, suffix);
return result;
}
long count();

View File

@ -143,6 +143,7 @@ public class HsOfficePartnerController implements HsOfficePartnersApi {
private void optionallyCreateExPartnerRelation(final HsOfficePartnerEntity saved, final HsOfficeRelationRealEntity previousPartnerRel) {
if (!saved.getPartnerRel().getUuid().equals(previousPartnerRel.getUuid())) {
// TODO.impl: we also need to use the new partner-person as the anchor
relationRepo.save(previousPartnerRel.toBuilder().uuid(null).type(EX_PARTNER).build());
}
}

View File

@ -4,6 +4,7 @@ import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.util.stream.Stream;
// HOWTO: convert data types for exchange between PostgreSQL and Java/Hibernate/JPA-Entities
@Converter(autoApply = true)
public class HsOfficePersonTypeConverter implements AttributeConverter<HsOfficePersonType, String> {

View File

@ -14,6 +14,7 @@ public class SystemProcess {
@Getter
private String stdOut;
@Getter
private String stdErr;
@ -21,7 +22,6 @@ public class SystemProcess {
this.processBuilder = new ProcessBuilder(command);
}
public String getCommand() {
return processBuilder.command().toString();
}

View File

@ -6,7 +6,7 @@ components:
HsOfficeCoopAssetsTransactionType:
type: string
enum:
- ADJUSTMENT
- REVERSAL
- DEPOSIT
- DISBURSAL
- TRANSFER
@ -32,15 +32,15 @@ components:
type: string
comment:
type: string
adjustedAssetTx:
revertedAssetTx:
$ref: '#/components/schemas/HsOfficeReferencedCoopAssetsTransaction'
adjustmentAssetTx:
reversalAssetTx:
$ref: '#/components/schemas/HsOfficeReferencedCoopAssetsTransaction'
HsOfficeReferencedCoopAssetsTransaction:
description:
Similar to `HsOfficeCoopAssetsTransaction` but without the self-referencing properties
(`adjustedAssetTx` and `adjustmentAssetTx`), to avoid recursive JSON.
(`revertedAssetTx` and `reversalAssetTx`), to avoid recursive JSON.
type: object
properties:
uuid:
@ -80,7 +80,7 @@ components:
maxLength: 48
comment:
type: string
reverseEntry.uuid:
revertedAssetTx.uuid:
type: string
format: uuid
required:

View File

@ -2,7 +2,7 @@ get:
tags:
- hs-office-coopAssets
description: 'Fetch a single asset transaction by its uuid, if visible for the current subject.'
operationId: getCoopAssetTransactionByUuid
operationId: getSingleCoopAssetTransactionByUuid
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'

View File

@ -3,7 +3,7 @@ get:
description: Returns the list of (optionally filtered) cooperative asset transactions which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-coopAssets
operationId: listCoopAssets
operationId: getListOfCoopAssets
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
@ -46,7 +46,7 @@ post:
summary: Adds a new cooperative asset transaction.
tags:
- hs-office-coopAssets
operationId: addCoopAssetsTransaction
operationId: postNewCoopAssetTransaction
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'

View File

@ -6,7 +6,7 @@ components:
HsOfficeCoopSharesTransactionType:
type: string
enum:
- ADJUSTMENT
- REVERSAL
- SUBSCRIPTION
- CANCELLATION
@ -27,15 +27,15 @@ components:
type: string
comment:
type: string
adjustedShareTx:
revertedShareTx:
$ref: '#/components/schemas/HsOfficeReferencedCoopSharesTransaction'
adjustmentShareTx:
reversalShareTx:
$ref: '#/components/schemas/HsOfficeReferencedCoopSharesTransaction'
HsOfficeReferencedCoopSharesTransaction:
description:
Similar to `HsOfficeCoopSharesTransaction` but without the self-referencing properties
(`adjustedShareTx` and `adjustmentShareTx`), to avoid recursive JSON.
(`revertedShareTx` and `reversalShareTx`), to avoid recursive JSON.
type: object
properties:
uuid:
@ -73,7 +73,7 @@ components:
maxLength: 48
comment:
type: string
adjustedShareTx.uuid:
revertedShareTx.uuid:
type: string
format: uuid
required:

View File

@ -2,7 +2,7 @@ get:
tags:
- hs-office-coopShares
description: 'Fetch a single share transaction by its uuid, if visible for the current subject.'
operationId: getCoopShareTransactionByUuid
operationId: getSingleCoopShareTransactionByUuid
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'

View File

@ -3,7 +3,7 @@ get:
description: Returns the list of (optionally filtered) cooperative share transactions which are visible to the current subject or any of it's assumed roles.
tags:
- hs-office-coopShares
operationId: listCoopShares
operationId: getListOfCoopShares
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
@ -46,7 +46,7 @@ post:
summary: Adds a new cooperative share transaction.
tags:
- hs-office-coopShares
operationId: addCoopSharesTransaction
operationId: postNewCoopSharesTransaction
parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles'

View File

@ -28,6 +28,9 @@ create table if not exists hs_office.relation
);
--//
-- TODO.impl: unique constraint, to prevent using the same person multiple times as a partner, or better:
-- ( anchorUuid, holderUuid, type)
-- ============================================================================
--changeset michael.hoennig:hs-office-relation-MAIN-TABLE-JOURNAL endDelimiter:--//

View File

@ -4,7 +4,7 @@
--changeset michael.hoennig:hs-office-coopshares-MAIN-TABLE endDelimiter:--//
-- ----------------------------------------------------------------------------
CREATE TYPE hs_office.CoopSharesTransactionType AS ENUM ('ADJUSTMENT', 'SUBSCRIPTION', 'CANCELLATION');
CREATE TYPE hs_office.CoopSharesTransactionType AS ENUM ('REVERSAL', 'SUBSCRIPTION', 'CANCELLATION');
CREATE CAST (character varying as hs_office.CoopSharesTransactionType) WITH INOUT AS IMPLICIT;
@ -17,7 +17,7 @@ create table if not exists hs_office.coopsharetx
valueDate date not null,
shareCount integer not null,
reference varchar(48) not null,
adjustedShareTxUuid uuid unique REFERENCES hs_office.coopsharetx(uuid) DEFERRABLE INITIALLY DEFERRED,
revertedShareTxUuid uuid unique REFERENCES hs_office.coopsharetx(uuid) DEFERRABLE INITIALLY DEFERRED,
comment varchar(512)
);
--//
@ -28,8 +28,8 @@ create table if not exists hs_office.coopsharetx
alter table hs_office.coopsharetx
add constraint reverse_entry_missing
check ( transactionType = 'ADJUSTMENT' and adjustedShareTxUuid is not null
or transactionType <> 'ADJUSTMENT' and adjustedShareTxUuid is null);
check ( transactionType = 'REVERSAL' and revertedShareTxUuid is not null
or transactionType <> 'REVERSAL' and revertedShareTxUuid is null);
--//
-- ============================================================================

View File

@ -27,12 +27,12 @@ begin
raise notice 'creating test coopSharesTransaction: %', givenPartnerNumber::text || givenMemberNumberSuffix;
subscriptionEntryUuid := uuid_generate_v4();
insert
into hs_office.coopsharetx(uuid, membershipuuid, transactiontype, valuedate, sharecount, reference, comment, adjustedShareTxUuid)
into hs_office.coopsharetx(uuid, membershipuuid, transactiontype, valuedate, sharecount, reference, comment, revertedShareTxUuid)
values
(uuid_generate_v4(), membership.uuid, 'SUBSCRIPTION', '2010-03-15', 4, 'ref '||givenPartnerNumber::text || givenMemberNumberSuffix||'-1', 'initial subscription', null),
(uuid_generate_v4(), membership.uuid, 'CANCELLATION', '2021-09-01', -2, 'ref '||givenPartnerNumber::text || givenMemberNumberSuffix||'-2', 'cancelling some', null),
(subscriptionEntryUuid, membership.uuid, 'SUBSCRIPTION', '2022-10-20', 2, 'ref '||givenPartnerNumber::text || givenMemberNumberSuffix||'-3', 'some subscription', null),
(uuid_generate_v4(), membership.uuid, 'ADJUSTMENT', '2022-10-21', -2, 'ref '||givenPartnerNumber::text || givenMemberNumberSuffix||'-4', 'some adjustment', subscriptionEntryUuid);
(uuid_generate_v4(), membership.uuid, 'REVERSAL', '2022-10-21', -2, 'ref '||givenPartnerNumber::text || givenMemberNumberSuffix||'-4', 'some reversal', subscriptionEntryUuid);
end; $$;
--//

View File

@ -4,7 +4,7 @@
--changeset michael.hoennig:hs-office-coopassets-MAIN-TABLE endDelimiter:--//
-- ----------------------------------------------------------------------------
CREATE TYPE hs_office.CoopAssetsTransactionType AS ENUM ('ADJUSTMENT',
CREATE TYPE hs_office.CoopAssetsTransactionType AS ENUM ('REVERSAL',
'DEPOSIT',
'DISBURSAL',
'TRANSFER',
@ -22,9 +22,9 @@ create table if not exists hs_office.coopassettx
membershipUuid uuid not null references hs_office.membership(uuid),
transactionType hs_office.CoopAssetsTransactionType not null,
valueDate date not null,
assetValue money not null,
assetValue numeric(12,2) not null, -- https://wiki.postgresql.org/wiki/Don't_Do_This#Don.27t_use_money
reference varchar(48) not null,
adjustedAssetTxUuid uuid unique REFERENCES hs_office.coopassettx(uuid) DEFERRABLE INITIALLY DEFERRED,
revertedAssetTxUuid uuid unique REFERENCES hs_office.coopassettx(uuid) DEFERRABLE INITIALLY DEFERRED,
comment varchar(512)
);
--//
@ -36,20 +36,20 @@ create table if not exists hs_office.coopassettx
alter table hs_office.coopassettx
add constraint reverse_entry_missing
check ( transactionType = 'ADJUSTMENT' and adjustedAssetTxUuid is not null
or transactionType <> 'ADJUSTMENT' and adjustedAssetTxUuid is null);
check ( transactionType = 'REVERSAL' and revertedAssetTxUuid is not null
or transactionType <> 'REVERSAL' and revertedAssetTxUuid is null);
--//
-- ============================================================================
--changeset michael.hoennig:hs-office-coopassets-ASSET-VALUE-CONSTRAINT endDelimiter:--//
-- ----------------------------------------------------------------------------
create or replace function hs_office.coopassetstx_check_positive_total(forMembershipUuid UUID, newAssetValue money)
create or replace function hs_office.coopassetstx_check_positive_total(forMembershipUuid UUID, newAssetValue numeric(12, 5))
returns boolean
language plpgsql as $$
declare
currentAssetValue money;
totalAssetValue money;
currentAssetValue numeric(12,2);
totalAssetValue numeric(12,2);
begin
select sum(cat.assetValue)
from hs_office.coopassettx cat

View File

@ -27,12 +27,12 @@ begin
raise notice 'creating test coopAssetsTransaction: %', givenPartnerNumber || givenMemberNumberSuffix;
lossEntryUuid := uuid_generate_v4();
insert
into hs_office.coopassettx(uuid, membershipuuid, transactiontype, valuedate, assetvalue, reference, comment, adjustedAssetTxUuid)
into hs_office.coopassettx(uuid, membershipuuid, transactiontype, valuedate, assetvalue, reference, comment, revertedAssetTxUuid)
values
(uuid_generate_v4(), membership.uuid, 'DEPOSIT', '2010-03-15', 320.00, 'ref '||givenPartnerNumber || givenMemberNumberSuffix||'-1', 'initial deposit', null),
(uuid_generate_v4(), membership.uuid, 'DISBURSAL', '2021-09-01', -128.00, 'ref '||givenPartnerNumber || givenMemberNumberSuffix||'-2', 'partial disbursal', null),
(lossEntryUuid, membership.uuid, 'DEPOSIT', '2022-10-20', 128.00, 'ref '||givenPartnerNumber || givenMemberNumberSuffix||'-3', 'some loss', null),
(uuid_generate_v4(), membership.uuid, 'ADJUSTMENT', '2022-10-21', -128.00, 'ref '||givenPartnerNumber || givenMemberNumberSuffix||'-3', 'some adjustment', lossEntryUuid);
(uuid_generate_v4(), membership.uuid, 'REVERSAL', '2022-10-21', -128.00, 'ref '||givenPartnerNumber || givenMemberNumberSuffix||'-3', 'some reversal', lossEntryUuid);
end; $$;
--//