diff --git a/pom.xml b/pom.xml
index 1c8e6176..b8887d15 100644
--- a/pom.xml
+++ b/pom.xml
@@ -177,7 +177,7 @@
dev.vality
damsel
- 1.692-70b59b9
+ 1.695-25e75a5
dev.vality
diff --git a/src/main/java/dev/vality/daway/dao/invoicing/iface/PaymentExchangeContextDao.java b/src/main/java/dev/vality/daway/dao/invoicing/iface/PaymentExchangeContextDao.java
new file mode 100644
index 00000000..32061aea
--- /dev/null
+++ b/src/main/java/dev/vality/daway/dao/invoicing/iface/PaymentExchangeContextDao.java
@@ -0,0 +1,17 @@
+package dev.vality.daway.dao.invoicing.iface;
+
+import dev.vality.dao.GenericDao;
+import dev.vality.daway.domain.tables.pojos.PaymentExchangeContext;
+import dev.vality.daway.exception.DaoException;
+import dev.vality.daway.model.InvoicingKey;
+
+import java.util.List;
+import java.util.Set;
+
+public interface PaymentExchangeContextDao extends GenericDao {
+
+ void saveBatch(List paymentExchangeContexts) throws DaoException;
+
+ void switchCurrent(Set invoicingKeys) throws DaoException;
+
+}
diff --git a/src/main/java/dev/vality/daway/dao/invoicing/impl/PaymentExchangeContextDaoImpl.java b/src/main/java/dev/vality/daway/dao/invoicing/impl/PaymentExchangeContextDaoImpl.java
new file mode 100644
index 00000000..65099d34
--- /dev/null
+++ b/src/main/java/dev/vality/daway/dao/invoicing/impl/PaymentExchangeContextDaoImpl.java
@@ -0,0 +1,82 @@
+package dev.vality.daway.dao.invoicing.impl;
+
+import dev.vality.dao.impl.AbstractGenericDao;
+import dev.vality.daway.dao.invoicing.iface.PaymentExchangeContextDao;
+import dev.vality.daway.domain.tables.pojos.PaymentExchangeContext;
+import dev.vality.daway.domain.tables.records.PaymentExchangeContextRecord;
+import dev.vality.daway.exception.DaoException;
+import dev.vality.daway.model.InvoicingKey;
+import dev.vality.mapper.RecordRowMapper;
+import org.jooq.Query;
+import org.jooq.impl.DSL;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static dev.vality.daway.domain.Tables.PAYMENT_EXCHANGE_CONTEXT;
+
+@Component
+public class PaymentExchangeContextDaoImpl extends AbstractGenericDao implements PaymentExchangeContextDao {
+
+ private final RowMapper paymentExchangeContextRowMapper;
+
+ public PaymentExchangeContextDaoImpl(DataSource dataSource) {
+ super(dataSource);
+ paymentExchangeContextRowMapper = new RecordRowMapper<>(PAYMENT_EXCHANGE_CONTEXT, PaymentExchangeContext.class);
+ }
+
+ @Override
+ public void saveBatch(List paymentExchangeContexts) throws DaoException {
+ List queries = paymentExchangeContexts.stream()
+ .map(paymentExchangeContext -> getDslContext().newRecord(
+ PAYMENT_EXCHANGE_CONTEXT, paymentExchangeContext))
+ .map(this::prepareInsertQuery)
+ .toList();
+ batchExecute(queries);
+ }
+
+ private Query prepareInsertQuery(PaymentExchangeContextRecord record) {
+ return getDslContext().insertInto(PAYMENT_EXCHANGE_CONTEXT)
+ .set(record)
+ .onConflict(
+ PAYMENT_EXCHANGE_CONTEXT.INVOICE_ID,
+ PAYMENT_EXCHANGE_CONTEXT.PAYMENT_ID,
+ PAYMENT_EXCHANGE_CONTEXT.SEQUENCE_ID,
+ PAYMENT_EXCHANGE_CONTEXT.CHANGE_ID
+ )
+ .doNothing();
+ }
+
+ @Override
+ public void switchCurrent(Set invoicingKeys) throws DaoException {
+ invoicingKeys.forEach(key -> {
+ setOldPaymentExchangeContextNotCurrent(key);
+ setLatestPaymentExchangeContextCurrent(key);
+ });
+ }
+
+ private void setOldPaymentExchangeContextNotCurrent(InvoicingKey key) {
+ execute(getDslContext().update(PAYMENT_EXCHANGE_CONTEXT)
+ .set(PAYMENT_EXCHANGE_CONTEXT.CURRENT, false)
+ .where(PAYMENT_EXCHANGE_CONTEXT.INVOICE_ID.eq(key.getInvoiceId())
+ .and(PAYMENT_EXCHANGE_CONTEXT.PAYMENT_ID.eq(key.getPaymentId()))
+ .and(PAYMENT_EXCHANGE_CONTEXT.CURRENT))
+ );
+ }
+
+ private void setLatestPaymentExchangeContextCurrent(InvoicingKey key) {
+ execute(getDslContext().update(PAYMENT_EXCHANGE_CONTEXT)
+ .set(PAYMENT_EXCHANGE_CONTEXT.CURRENT, true)
+ .where(PAYMENT_EXCHANGE_CONTEXT.ID.eq(
+ DSL.select(DSL.max(PAYMENT_EXCHANGE_CONTEXT.ID))
+ .from(PAYMENT_EXCHANGE_CONTEXT)
+ .where(PAYMENT_EXCHANGE_CONTEXT.INVOICE_ID.eq(key.getInvoiceId())
+ .and(PAYMENT_EXCHANGE_CONTEXT.PAYMENT_ID.eq(key.getPaymentId())))
+ ))
+ );
+ }
+}
diff --git a/src/main/java/dev/vality/daway/factory/cash/flow/CashFlowFactory.java b/src/main/java/dev/vality/daway/factory/cash/flow/CashFlowFactory.java
index 6fc56213..e9df3225 100644
--- a/src/main/java/dev/vality/daway/factory/cash/flow/CashFlowFactory.java
+++ b/src/main/java/dev/vality/daway/factory/cash/flow/CashFlowFactory.java
@@ -37,6 +37,12 @@ public static List build(List cashFlowPostings,
pcf.setAmount(cf.getVolume().getAmount());
pcf.setCurrencyCode(cf.getVolume().getCurrency().getSymbolicCode());
pcf.setDetails(cf.getDetails());
+ if (cf.isSetExchangeContext()) {
+ pcf.setExchangeSourceCurrencyCode(cf.getExchangeContext().getSourceCurrency());
+ pcf.setExchangeDestinationCurrencyCode(cf.getExchangeContext().getDestinationCurrency());
+ pcf.setExchangeRateRationalP(cf.getExchangeContext().getExchangeRate().getP());
+ pcf.setExchangeRateRationalQ(cf.getExchangeContext().getExchangeRate().getQ());
+ }
return pcf;
}).collect(Collectors.toList());
}
diff --git a/src/main/java/dev/vality/daway/handler/wrapper/payment/PaymentExchangeContextWrapperHandler.java b/src/main/java/dev/vality/daway/handler/wrapper/payment/PaymentExchangeContextWrapperHandler.java
new file mode 100644
index 00000000..4b4e44f6
--- /dev/null
+++ b/src/main/java/dev/vality/daway/handler/wrapper/payment/PaymentExchangeContextWrapperHandler.java
@@ -0,0 +1,39 @@
+package dev.vality.daway.handler.wrapper.payment;
+
+import dev.vality.daway.dao.invoicing.iface.PaymentExchangeContextDao;
+import dev.vality.daway.domain.tables.pojos.PaymentExchangeContext;
+import dev.vality.daway.handler.wrapper.WrapperHandler;
+import dev.vality.daway.model.PaymentWrapper;
+import dev.vality.daway.util.PaymentWrapperUtil;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@RequiredArgsConstructor
+@Component
+public class PaymentExchangeContextWrapperHandler implements WrapperHandler {
+
+ private final PaymentExchangeContextDao paymentExchangeContextDao;
+
+ @Override
+ public boolean accept(List wrappers) {
+ return wrappers.stream()
+ .map(PaymentWrapper::getPaymentExchangeContext)
+ .anyMatch(Objects::nonNull);
+ }
+
+ @Override
+ public void saveBatch(List wrappers) {
+ List processableWrappers = wrappers.stream()
+ .filter(paymentWrapper -> Objects.nonNull(paymentWrapper.getPaymentExchangeContext()))
+ .collect(Collectors.toList());
+ List paymentExchangeContexts = processableWrappers.stream()
+ .map(PaymentWrapper::getPaymentExchangeContext)
+ .collect(Collectors.toList());
+ paymentExchangeContextDao.saveBatch(paymentExchangeContexts);
+ paymentExchangeContextDao.switchCurrent(PaymentWrapperUtil.getInvoicingKeys(processableWrappers));
+ }
+}
diff --git a/src/main/java/dev/vality/daway/mapper/payment/InvoicePaymentExchangeContextChangedMapper.java b/src/main/java/dev/vality/daway/mapper/payment/InvoicePaymentExchangeContextChangedMapper.java
new file mode 100644
index 00000000..5e2873e4
--- /dev/null
+++ b/src/main/java/dev/vality/daway/mapper/payment/InvoicePaymentExchangeContextChangedMapper.java
@@ -0,0 +1,73 @@
+package dev.vality.daway.mapper.payment;
+
+import dev.vality.damsel.base.Rational;
+import dev.vality.damsel.domain.ExchangeContext;
+import dev.vality.damsel.payment_processing.InvoiceChange;
+import dev.vality.damsel.payment_processing.InvoicePaymentChange;
+import dev.vality.damsel.payment_processing.InvoicePaymentExchangeContextChanged;
+import dev.vality.daway.domain.tables.pojos.PaymentExchangeContext;
+import dev.vality.daway.mapper.Mapper;
+import dev.vality.daway.model.InvoicingKey;
+import dev.vality.daway.model.PaymentWrapper;
+import dev.vality.geck.common.util.TypeUtil;
+import dev.vality.geck.filter.Filter;
+import dev.vality.geck.filter.PathConditionFilter;
+import dev.vality.geck.filter.condition.IsNullCondition;
+import dev.vality.geck.filter.rule.PathConditionRule;
+import dev.vality.machinegun.eventsink.MachineEvent;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class InvoicePaymentExchangeContextChangedMapper implements Mapper {
+
+ private Filter filter = new PathConditionFilter(new PathConditionRule(
+ "invoice_payment_change.payload.invoice_payment_exchange_context_changed",
+ new IsNullCondition().not()));
+
+ @Override
+ public PaymentWrapper map(InvoiceChange change, MachineEvent event, Integer changeId) {
+ InvoicePaymentChange invoicePaymentChange = change.getInvoicePaymentChange();
+ String invoiceId = event.getSourceId();
+ String paymentId = invoicePaymentChange.getId();
+ long sequenceId = event.getEventId();
+ log.info("Start mapping payment exchange context change, sequenceId='{}', changeId='{}', invoiceId='{}', "
+ + "paymentId='{}'",
+ sequenceId, changeId, invoiceId, paymentId);
+
+ InvoicePaymentExchangeContextChanged exchangeContextChanged =
+ invoicePaymentChange.getPayload().getInvoicePaymentExchangeContextChanged();
+ ExchangeContext exchangeContext = exchangeContextChanged.getExchangeContext();
+ Rational exchangeRate = exchangeContext.getExchangeRate();
+
+ PaymentExchangeContext paymentExchangeContext = new PaymentExchangeContext();
+ paymentExchangeContext.setWtime(null);
+ paymentExchangeContext.setId(null);
+ paymentExchangeContext.setChangeId(changeId);
+ paymentExchangeContext.setSequenceId(sequenceId);
+ paymentExchangeContext.setPaymentId(paymentId);
+ paymentExchangeContext.setInvoiceId(invoiceId);
+ paymentExchangeContext.setCurrent(true);
+ paymentExchangeContext.setEventCreatedAt(TypeUtil.stringToLocalDateTime(event.getCreatedAt()));
+ paymentExchangeContext.setSourceCurrencyCode(exchangeContext.getSourceCurrency());
+ paymentExchangeContext.setDestinationCurrencyCode(exchangeContext.getDestinationCurrency());
+ paymentExchangeContext.setExchangeRateRationalP(exchangeRate.getP());
+ paymentExchangeContext.setExchangeRateRationalQ(exchangeRate.getQ());
+
+ PaymentWrapper paymentWrapper = new PaymentWrapper();
+ paymentWrapper.setKey(InvoicingKey.buildKey(invoiceId, paymentId));
+ paymentWrapper.setPaymentExchangeContext(paymentExchangeContext);
+ log.info("Payment exchange context has been mapped, sequenceId='{}', changeId='{}', invoiceId='{}', "
+ + "paymentId='{}'",
+ sequenceId, changeId, invoiceId, paymentId);
+ return paymentWrapper;
+ }
+
+ @Override
+ public Filter getFilter() {
+ return filter;
+ }
+}
diff --git a/src/main/java/dev/vality/daway/model/PaymentWrapper.java b/src/main/java/dev/vality/daway/model/PaymentWrapper.java
index 2630d219..80d5502e 100644
--- a/src/main/java/dev/vality/daway/model/PaymentWrapper.java
+++ b/src/main/java/dev/vality/daway/model/PaymentWrapper.java
@@ -18,6 +18,7 @@ public class PaymentWrapper {
private PaymentRiskData paymentRiskData;
private PaymentFee paymentFee;
private PaymentRoute paymentRoute;
+ private PaymentExchangeContext paymentExchangeContext;
private CashFlowWrapper cashFlowWrapper;
private PaymentCashChange paymentCashChange;
private InvoicingKey key;
diff --git a/src/main/resources/db/migration/V52__add_payment_exchange_context.sql b/src/main/resources/db/migration/V52__add_payment_exchange_context.sql
new file mode 100644
index 00000000..96eb08fa
--- /dev/null
+++ b/src/main/resources/db/migration/V52__add_payment_exchange_context.sql
@@ -0,0 +1,24 @@
+CREATE TABLE IF NOT EXISTS dw.payment_exchange_context
+(
+ id bigserial NOT NULL,
+ event_created_at timestamp without time zone NOT NULL,
+ invoice_id character varying NOT NULL,
+ payment_id character varying NOT NULL,
+ source_currency_code character varying NOT NULL,
+ destination_currency_code character varying NOT NULL,
+ exchange_rate_rational_p bigint NOT NULL,
+ exchange_rate_rational_q bigint NOT NULL,
+ current boolean NOT NULL DEFAULT false,
+ wtime timestamp without time zone NOT NULL DEFAULT (now() AT TIME ZONE 'utc'::text),
+ sequence_id bigint,
+ change_id integer,
+
+ CONSTRAINT payment_exchange_context_pkey PRIMARY KEY (id),
+ CONSTRAINT payment_exchange_context_uniq UNIQUE (invoice_id, payment_id, sequence_id, change_id)
+);
+
+ALTER TABLE dw.cash_flow
+ ADD COLUMN IF NOT EXISTS exchange_source_currency_code character varying,
+ ADD COLUMN IF NOT EXISTS exchange_destination_currency_code character varying,
+ ADD COLUMN IF NOT EXISTS exchange_rate_rational_p bigint,
+ ADD COLUMN IF NOT EXISTS exchange_rate_rational_q bigint;
diff --git a/src/test/java/dev/vality/daway/TestData.java b/src/test/java/dev/vality/daway/TestData.java
index 173e07f7..105c6135 100644
--- a/src/test/java/dev/vality/daway/TestData.java
+++ b/src/test/java/dev/vality/daway/TestData.java
@@ -1,5 +1,6 @@
package dev.vality.daway;
+import dev.vality.damsel.base.Rational;
import dev.vality.damsel.domain.*;
import dev.vality.damsel.domain.CashFlowAccount;
import dev.vality.damsel.domain.InvoicePaymentChargeback;
@@ -14,7 +15,10 @@
import dev.vality.daway.domain.enums.*;
import dev.vality.daway.domain.tables.pojos.Chargeback;
import dev.vality.daway.domain.tables.pojos.FistfulCashFlow;
+import dev.vality.daway.domain.tables.pojos.PaymentExchangeContext;
import dev.vality.daway.domain.tables.pojos.WithdrawalAdjustment;
+import dev.vality.daway.model.InvoicingKey;
+import dev.vality.daway.model.PaymentWrapper;
import dev.vality.fistful.account.Account;
import dev.vality.fistful.base.Realm;
import dev.vality.fistful.cashflow.FinalCashFlow;
@@ -234,6 +238,70 @@ public static String randomString() {
return UUID.randomUUID().toString();
}
+ public static ExchangeContext createExchangeContext() {
+ return createExchangeContext("RUB", "USD", 60797502L, 1000000L);
+ }
+
+ public static ExchangeContext createExchangeContext(String sourceCurrencyCode,
+ String destinationCurrencyCode,
+ Long rationalP,
+ Long rationalQ) {
+ return new ExchangeContext(sourceCurrencyCode, destinationCurrencyCode, new Rational(rationalP, rationalQ));
+ }
+
+ public static FinalCashFlowPosting createPaymentCashFlowPosting() {
+ return new FinalCashFlowPosting()
+ .setSource(new FinalCashFlowAccount()
+ .setAccountId(1)
+ .setAccountType(CashFlowAccount.merchant(MerchantCashFlowAccount.settlement)))
+ .setDestination(new FinalCashFlowAccount()
+ .setAccountId(2)
+ .setAccountType(CashFlowAccount.system(SystemCashFlowAccount.settlement)))
+ .setVolume(new Cash(1000L, new CurrencyRef("RUB")));
+ }
+
+ public static FinalCashFlowPosting createPaymentCashFlowPostingWithExchangeContext() {
+ return createPaymentCashFlowPosting()
+ .setExchangeContext(createExchangeContext());
+ }
+
+ public static MachineEvent createInvoiceEvent(String invoiceId, Long sequenceId, LocalDateTime createdAt) {
+ return new MachineEvent()
+ .setSourceId(invoiceId)
+ .setEventId(sequenceId)
+ .setCreatedAt(TypeUtil.temporalToString(createdAt));
+ }
+
+ public static InvoiceChange createInvoicePaymentExchangeContextChanged(String paymentId) {
+ return InvoiceChange.invoice_payment_change(new InvoicePaymentChange()
+ .setId(paymentId)
+ .setPayload(InvoicePaymentChangePayload.invoice_payment_exchange_context_changed(
+ new InvoicePaymentExchangeContextChanged(createExchangeContext()))));
+ }
+
+ public static PaymentWrapper createPaymentExchangeContextWrapper(String invoiceId,
+ String paymentId,
+ Long sequenceId,
+ Integer changeId,
+ Long exchangeRateP) {
+ PaymentExchangeContext paymentExchangeContext = new PaymentExchangeContext();
+ paymentExchangeContext.setEventCreatedAt(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS));
+ paymentExchangeContext.setInvoiceId(invoiceId);
+ paymentExchangeContext.setPaymentId(paymentId);
+ paymentExchangeContext.setSourceCurrencyCode("RUB");
+ paymentExchangeContext.setDestinationCurrencyCode("USD");
+ paymentExchangeContext.setExchangeRateRationalP(exchangeRateP);
+ paymentExchangeContext.setExchangeRateRationalQ(1000000L);
+ paymentExchangeContext.setSequenceId(sequenceId);
+ paymentExchangeContext.setChangeId(changeId);
+ paymentExchangeContext.setCurrent(true);
+
+ PaymentWrapper paymentWrapper = new PaymentWrapper();
+ paymentWrapper.setKey(InvoicingKey.buildKey(invoiceId, paymentId));
+ paymentWrapper.setPaymentExchangeContext(paymentExchangeContext);
+ return paymentWrapper;
+ }
+
public static CountryObject buildCountryObject() {
Country country = new Country();
country.setName(randomString());
diff --git a/src/test/java/dev/vality/daway/factory/cash/flow/CashFlowFactoryTest.java b/src/test/java/dev/vality/daway/factory/cash/flow/CashFlowFactoryTest.java
new file mode 100644
index 00000000..38f05691
--- /dev/null
+++ b/src/test/java/dev/vality/daway/factory/cash/flow/CashFlowFactoryTest.java
@@ -0,0 +1,41 @@
+package dev.vality.daway.factory.cash.flow;
+
+import dev.vality.damsel.domain.FinalCashFlowPosting;
+import dev.vality.daway.TestData;
+import dev.vality.daway.domain.enums.PaymentChangeType;
+import dev.vality.daway.domain.tables.pojos.CashFlow;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class CashFlowFactoryTest {
+
+ @Test
+ void buildWithExchangeContextTest() {
+ FinalCashFlowPosting posting = TestData.createPaymentCashFlowPostingWithExchangeContext();
+
+ CashFlow cashFlow = CashFlowFactory.build(List.of(posting), 1L, PaymentChangeType.payment).get(0);
+
+ assertEquals("RUB", cashFlow.getExchangeSourceCurrencyCode());
+ assertEquals("USD", cashFlow.getExchangeDestinationCurrencyCode());
+ assertEquals(60797502L, cashFlow.getExchangeRateRationalP());
+ assertEquals(1000000L, cashFlow.getExchangeRateRationalQ());
+ }
+
+ @Test
+ void buildWithoutExchangeContextTest() {
+ CashFlow cashFlow = CashFlowFactory.build(
+ List.of(TestData.createPaymentCashFlowPosting()),
+ 1L,
+ PaymentChangeType.payment
+ ).get(0);
+
+ assertNull(cashFlow.getExchangeSourceCurrencyCode());
+ assertNull(cashFlow.getExchangeDestinationCurrencyCode());
+ assertNull(cashFlow.getExchangeRateRationalP());
+ assertNull(cashFlow.getExchangeRateRationalQ());
+ }
+}
diff --git a/src/test/java/dev/vality/daway/mapper/payment/InvoicePaymentExchangeContextChangedMapperTest.java b/src/test/java/dev/vality/daway/mapper/payment/InvoicePaymentExchangeContextChangedMapperTest.java
new file mode 100644
index 00000000..b3ec968b
--- /dev/null
+++ b/src/test/java/dev/vality/daway/mapper/payment/InvoicePaymentExchangeContextChangedMapperTest.java
@@ -0,0 +1,43 @@
+package dev.vality.daway.mapper.payment;
+
+import dev.vality.damsel.payment_processing.InvoiceChange;
+import dev.vality.daway.TestData;
+import dev.vality.daway.domain.tables.pojos.PaymentExchangeContext;
+import dev.vality.daway.model.PaymentWrapper;
+import dev.vality.machinegun.eventsink.MachineEvent;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class InvoicePaymentExchangeContextChangedMapperTest {
+
+ private final InvoicePaymentExchangeContextChangedMapper mapper =
+ new InvoicePaymentExchangeContextChangedMapper();
+
+ @Test
+ void mapTest() {
+ LocalDateTime createdAt = LocalDateTime.now().truncatedTo(ChronoUnit.MICROS);
+ MachineEvent event = TestData.createInvoiceEvent("invoice_id", 42L, createdAt);
+ InvoiceChange change = TestData.createInvoicePaymentExchangeContextChanged("payment_id");
+
+ PaymentWrapper wrapper = mapper.map(change, event, 7);
+ PaymentExchangeContext paymentExchangeContext = wrapper.getPaymentExchangeContext();
+
+ assertEquals("invoice_id", wrapper.getKey().getInvoiceId());
+ assertEquals("payment_id", wrapper.getKey().getPaymentId());
+ assertEquals("invoice_id", paymentExchangeContext.getInvoiceId());
+ assertEquals("payment_id", paymentExchangeContext.getPaymentId());
+ assertEquals(createdAt, paymentExchangeContext.getEventCreatedAt());
+ assertEquals(42L, paymentExchangeContext.getSequenceId());
+ assertEquals(7, paymentExchangeContext.getChangeId());
+ assertTrue(paymentExchangeContext.getCurrent());
+ assertEquals("RUB", paymentExchangeContext.getSourceCurrencyCode());
+ assertEquals("USD", paymentExchangeContext.getDestinationCurrencyCode());
+ assertEquals(60797502L, paymentExchangeContext.getExchangeRateRationalP());
+ assertEquals(1000000L, paymentExchangeContext.getExchangeRateRationalQ());
+ }
+}
diff --git a/src/test/java/dev/vality/daway/service/PaymentWrapperServiceTest.java b/src/test/java/dev/vality/daway/service/PaymentWrapperServiceTest.java
index b8cb0646..5f2e48ff 100644
--- a/src/test/java/dev/vality/daway/service/PaymentWrapperServiceTest.java
+++ b/src/test/java/dev/vality/daway/service/PaymentWrapperServiceTest.java
@@ -95,6 +95,7 @@ private List preparePaymentWrappers() {
.map(PaymentWrapper::getPayment)
.forEach(payment -> payment.setEventCreatedAt(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS)));
paymentWrappers.forEach(pw -> {
+ pw.setPaymentExchangeContext(null);
pw.setCashFlowWrapper(new CashFlowWrapper(
RandomBeans.random(CashFlowLink.class),
RandomBeans.randomListOf(random.nextLong(100), 3, CashFlow.class)
@@ -168,4 +169,28 @@ void testPaymentFeeWithEmptyWrapper() {
assertDoesNotThrow(() -> paymentWrapperService.save(List.of(wrapperWithFee, emptyWrapper)));
}
+
+ @Test
+ void paymentExchangeContextCurrentSwitchTest() {
+ String invoiceId = TestData.randomString();
+ String paymentId = TestData.randomString();
+
+ PaymentWrapper firstWrapper =
+ TestData.createPaymentExchangeContextWrapper(invoiceId, paymentId, 1L, 1, 60797502L);
+ PaymentWrapper secondWrapper =
+ TestData.createPaymentExchangeContextWrapper(invoiceId, paymentId, 2L, 1, 70797502L);
+
+ paymentWrapperService.save(List.of(firstWrapper, secondWrapper));
+
+ assertEquals(2, countPaymentEntity(jdbcTemplate, "payment_exchange_context", invoiceId, paymentId, false));
+ assertEquals(1, countPaymentEntity(jdbcTemplate, "payment_exchange_context", invoiceId, paymentId, true));
+ assertEquals(70797502L, jdbcTemplate.queryForObject("""
+ SELECT exchange_rate_rational_p
+ FROM dw.payment_exchange_context
+ WHERE invoice_id = ? AND payment_id = ? AND current
+ """,
+ Long.class,
+ invoiceId,
+ paymentId));
+ }
}
diff --git a/src/test/java/dev/vality/daway/utils/PaymentWrapperTestUtil.java b/src/test/java/dev/vality/daway/utils/PaymentWrapperTestUtil.java
index 7df92daf..bd70afd8 100644
--- a/src/test/java/dev/vality/daway/utils/PaymentWrapperTestUtil.java
+++ b/src/test/java/dev/vality/daway/utils/PaymentWrapperTestUtil.java
@@ -27,6 +27,9 @@ public static void setCurrent(PaymentWrapper wrapper, boolean current) {
if (wrapper.getPaymentRoute() != null) {
wrapper.getPaymentRoute().setCurrent(current);
}
+ if (wrapper.getPaymentExchangeContext() != null) {
+ wrapper.getPaymentExchangeContext().setCurrent(current);
+ }
if (wrapper.getCashFlowWrapper() != null) {
wrapper.getCashFlowWrapper().getCashFlowLink().setCurrent(current);
}
@@ -69,6 +72,10 @@ public static void setInvoiceIdAndPaymentId(PaymentWrapper wrapper, String invoi
wrapper.getPaymentRoute().setInvoiceId(invoiceId);
wrapper.getPaymentRoute().setPaymentId(paymentId);
}
+ if (wrapper.getPaymentExchangeContext() != null) {
+ wrapper.getPaymentExchangeContext().setInvoiceId(invoiceId);
+ wrapper.getPaymentExchangeContext().setPaymentId(paymentId);
+ }
if (wrapper.getCashFlowWrapper() != null) {
wrapper.getCashFlowWrapper().getCashFlowLink().setInvoiceId(invoiceId);
wrapper.getCashFlowWrapper().getCashFlowLink().setPaymentId(paymentId);