Перейти к содержанию

FuelProcessing.Data — Data Access Layer

Обзор

FuelProcessing.Data — это уровень доступа к данным, содержащий репозитории, Entity Framework контекст, API клиенты для интеграции с ВИНК и бизнес-сервисы.

Структура

FuelProcessing.Data/
├── Context/
│   ├── DataContext.cs           # Основной EF DbContext
│   ├── BuildConfigs/            # IEntityTypeConfiguration реализации
│   │   ├── CompanyConfiguration.cs
│   │   └── DirectContractOverdraftResetRequestConfiguration.cs
│   └── Seed/                    # Начальные данные (seed data)
│       ├── AdminConfiguration.cs
│       ├── RoleConfiguration.cs
│       ├── SystemConfigConfiguration.cs
│       └── SystemSettingsConfigureation.cs
├── Repository/
│   ├── Base/
│   │   ├── BaseRepository.cs    # Базовый класс репозитория
│   │   └── ApiBaseRepository.cs # Для API операций
│   ├── CardRepository.cs
│   ├── CompanyRepository.cs
│   ├── DirectContractRepository.cs
│   ├── FinanceTransactionRepository.cs
│   ├── ContractTermRepository.cs
│   ├── ContractTermTemplateRepository.cs
│   ├── UserRepository.cs
│   ├── ReportRepository.cs
│   ├── NewsRepository.cs
│   ├── CardChangeLogRepository.cs
│   ├── CurrentContractBalanceRepository.cs
│   ├── ContractPayInfoRepository.cs
│   ├── CardGroupRepository.cs
│   ├── FuelTypeRepository.cs
│   ├── FuelTypeForMapRepository.cs
│   ├── NewsCompanyRepository.cs
│   ├── RegionDirectContractWithVendorDiscountRepository.cs
│   └── ... (17 репозиториев)
├── Mapping/                     # AutoMapper профили
├── Helpers/                     # Вспомогательные классы
├── Migrations/                  # EF Core миграции (200+ файлов)
├── Services/                    # Бизнес-сервисы
├── Workers/                     # Фоновые задачи
└── LoggerConfig.cs              # Конфигурация Serilog

DataContext

Entity Framework Core контекст с PostgreSQL.

Базовый класс

public class DataContext : IdentityDbContext<
    User, Role, int,
    IdentityUserClaim<int>, UserRole, IdentityUserLogin<int>,
    IdentityRoleClaim<int>, IdentityUserToken<int>>
{
    public DataContext(DbContextOptions<DataContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
    }

    public override EntityEntry<TEntity> Update<TEntity>(TEntity entity)
    {
        if (entity is Entity entityItem)
            entityItem.LastModifed = DateTime.UtcNow;
        SaveChanges();
        return base.Update(entity);
    }
}

DbSet Properties (70+ сущностей)

DbSet Описание
Companies Компании
Cards Топливные карты
CardGroups Группы карт
CardOwners Владельцы карт
CardOwnerLimits Лимиты владельцев
CardLogs Логи изменений карт
CardChangeLogs История изменений
IssuingСards Выдачи карт
DirectContracts Прямые договоры между компаниями
DirectContractsWithVendor Прямые договоры с ВИНК
DirectContractOverdraftResetRequests Запросы сброса овердрафта
ContractTerms Условия по договору
ContractTermTemplates Шаблоны условий по договору
ContractTermTemplatePlans Запланированные шаблоны скидок
ContractPayInfos Оплаты по договору
ContractPayInfoDatas Данные о предыдущих платежах
CurrentContractBalances Текущие балансы
CurrentComissionBalances Баланс по комиссиям
CurrentTemporaryOverdrafts Изменения временного овердрафта
FinanceTransaction Финансовые транзакции
FinanceTransactionParts Части финансовой транзакции
DeletedFinanceTransactionForReports Удаленные транзакции для отчетов
MinusBalanceTransactionToDirectContracts Транзакции при отрицательном балансе
GasStations Заправки (АЗС)
GasStationsForRouting Заправки для построения маршрутов
FuelOnGasStations Топливо на АЗС
FuelOnGasStationsForRouting Цены заправок для маршрутов
FuelTypes Виды топлива (АИ-96, дизель и т.д.)
FuelCategories Категории топлива (газ, бензин)
FuelTypeVink Названия по версии ВИНК
FuelTypeVinkForRouting Виды топлива по версии ВИНК для маршрута
FuelTypeVinkDiscounts Скидки на топливо ВИНК по договору
FuelPriceForTemplates Цена для топлива по шаблону
FuelPriceForTemplatePlans Запланированная цена топлива по шаблону
RosneftVinkFuelTypes Типы топлива Роснефть
GlobaltruckVinkFuelTypes Типы топлива Globaltruck
GasStationBrands Бренды заправок
GasStationVinkBrands Бренды заправок по ВИНК
Regions Регионы
ApiRegionVinks Регионы по версии ВИНК
Tracks Трассы
Users Пользователи (Identity)
Roles Роли (Identity)
OrganisationInfo Информация по организациям
Resources Ресурсы (локализация)
Cultures Культуры (локализация)
SystemSettings Настройки системы
SystemConfigs Конфиги системы
SystemDatas Системные настройки
ApiMonitoring Данные синхронизации
MonitorProcessInfos Данные мониторинга
ApiCardInfos Данные API по карте
ApiCardGroupInfos Данные API по группе
ApiLimitInfo Данные API по лимитам
Limits Лимиты
LimitVinkHistory История лимитов ВИНК
Currencies Валюты
CompanySettings Настройки компаний
News Новости
NewsCompanies Новости, которые посмотрела компания
Reports Отчеты
VinkDiscountForTemplates Шаблон скидок ВИНК
VinkDiscountForTemplatesPlan Запланированные скидки ВИНК
VinkDiscountContractTemplatesPlan Планирование шаблона ВИНК
AccountReceivables Таблица должников
CommentsAndAccountReceivable Комментарии к дебиторке
UserAccountReceivableNoticeViews Представления уведомлений
BalanceActions Действия с балансом
StsCards Данные СТС
DirectContractOverdraftDateTimes Изменения состояния овердрафтов
MonitoringTransactions Мониторинг транзакций
TransactionRequestFaileds Неудавшиеся транзакции
TaskLimits Задачи лимитов
TaskBlocks Задачи блокировок
TaskReports Задачи на формирование отчетов
OfflineTaskBlocks Оффлайн задачи блокировок
OfflineTaskLimits Оффлайн задачи лимитов
OfflineHistories Оффлайн история
RecalculateTransactionTasks Задачи пересчета транзакций
NoFuelGoods Товары не топлива
CardTaskBlockResponses Ответы задач блокировки карт
CardOwnerCardLogs Логи владельцев карт
SummaryContractBalances Сводки по балансам
SummaryComissions Сводки по комиссиям

Конфигурация

// Startup.cs / Program.cs
services.AddDbContextPool<DataContext>(options =>
    options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))
);

Entity Framework Configurations

IEntityTypeConfiguration Implementations

Файлы в Context/BuildConfigs/:

Класс Сущность Назначение
CompanyConfiguration Company JSON конвертеры для SelfDirectContarctWithWink и CardTypes
DirectContractOverdraftResetRequestConfiguration DirectContractOverdraftResetRequest Конфигурация запросов сброса овердрафта

Seed Configurations

Файлы в Context/Seed/:

Класс Назначение
AdminConfiguration Создание администратора (info@wellsoft.pro)
RoleConfiguration Инициализация ролей пользователей
SystemConfigConfiguration Начальные системные конфиги
SystemSettingsConfigureation Начальные настройки системы

Репозитории

Базовый репозиторий

public class BaseRepository<T> : ISelfTransientLifetime where T : Entity
{
    protected readonly DataContext _context;
    public DbSet<T> entities;

    // CRUD операции
    public virtual IQueryable<T> GetAll()
    public virtual IQueryable<T> GetAllForRead()  // AsNoTracking
    public virtual T GetById(int id)
    public virtual T Add(T entity, bool isTransaction = false)
    public virtual void Update(T entity, bool isTransaction = false)
    public virtual void Delete(int id, bool isTransaction = false)
    public virtual void Delete(T entity, bool isTransaction = false)
    public virtual void AddRange(IEnumerable<T> entityArr, bool isTransaction = false)
    public virtual void UpdateRange(IEnumerable<T> entityArr, bool isTransaction = false)
    public virtual void RemoveRange(IEnumerable<T> entityArr, bool isTransaction = false)
    public virtual void Save()
    public virtual async Task SaveAsync()
}

Особенности: - Автоматическое обновление LastModifed при изменении - Интеграция с LogUserActionService для логирования - Параметр isTransaction для пакетных операций

ApiBaseRepository

public class ApiBaseRepository<T> : BaseRepository<T> where T : Entity
{
    // Помечает операции как выполняемые API (блокирует лог)
    public bool IsApiExecutor { get; set; } = true;
}

Список репозиториев

Репозиторий Базовый класс Особые методы
CardRepository BaseRepository<Card> GetByNumber(), CheckCompany(), UpdateStatusHistory(), UpdateWithTrackActivity(), MassBlockCard()
CompanyRepository BaseRepository<Company> GetAll() фильтрует IsBrandCompany = false
DirectContractRepository BaseRepository<DirectContract> При Add() создает CurrentContractBalance, при Delete() устанавливает IsHidden = true
FinanceTransactionRepository BaseRepository<FinanceTransaction> Базовая реализация
ContractTermRepository BaseRepository<ContractTerm> Базовая реализация
ContractTermTemplateRepository BaseRepository<ContractTermTemplate> Базовая реализация
UserRepository BaseRepository<User> Базовая реализация
ReportRepository BaseRepository<Report> GetAll(int companyId) с фильтрацией по ролям
NewsRepository BaseRepository<News> Базовая реализация
CardChangeLogRepository BaseRepository<CardChangeLog> Базовая реализация
CurrentContractBalanceRepository BaseRepository<CurrentContractBalance> Базовая реализация
ContractPayInfoRepository BaseRepository<ContractPayInfo> Базовая реализация
CardGroupRepository BaseRepository<CardGroup> Базовая реализация
FuelTypeRepository BaseRepository<FuelType> Базовая реализация
FuelTypeForMapRepository BaseRepository<FuelTypeForMap> Базовая реализация
NewsCompanyRepository BaseRepository<NewsCompany> Базовая реализация
RegionDirectContractWithVendorDiscountRepository BaseRepository<RegionDirectContractWithVendorDiscount> Базовая реализация

CardRepository - Особенности

public class CardRepository : BaseRepository<Card>
{
    // Поиск карты по номеру
    public Card GetByNumber(string number)

    // Проверка компании на доступ к перепродаже
    public void CheckCompany(Card card)

    // Логирование изменений статуса блокировки
    public void UpdateStatusHistory(Card card, bool isTransaction = false)
    public void UpdateStatusHistoryBatch(IEnumerable<Card> cards)

    // Обновление с отслеживанием активности для синхронизации с ВИНК
    public void UpdateWithTrackActivity(Card entity, bool isTransaction = false, string? comment = "")

    // Массовая блокировка карт
    public void MassBlockCard(List<Card> entityList, string? comment = "")
}

Статусы синхронизации: - StatusSyncCard.Синхронизирован - синхронизировано - StatusSyncCard.ВПроцессеСинхронизации - в процессе - StatusSyncCard.Неопределен - не определен

Миграции

Структура

FuelProcessing.Data/Migrations/
├── 20210404101024_Initial.cs           # Первичная миграция
├── 20210404135633_companyAndSeed.cs    # Компании и начальные данные
├── 20210406081253_initCoreModels.cs    # Инициализация основных моделей
├── 20210427103003_cards.cs             # Карты
├── 20210422123758_direactContracWithWink.cs  # Прямые договоры с ВИНК
├── 20210524131821_apisettingscontract.cs     # API настройки контрактов
├── 20210525143440_transactiontype.cs         # Типы транзакций
├── 20210617165923_GroupSync.cs              # Групповая синхронизация
├── 20210715101233_payInfo.cs                # Информация об оплатах
├── 20210803122651_fuelTemplatePrice.cs      # Цены топлива по шаблону
├── 20210903121758_transactionUtc.cs         # UTC время транзакций
├── 20211117063623_addSystemDatas.cs         # Системные данные
├── 20211203104405_ditributorFields.cs       # Поля дистрибьютора
├── 20220314115703_AddMonitoringTransactions.cs # Мониторинг транзакций
├── 20220329101620_FixUser.cs                # Исправление пользователя
├── 20220408104008_addOffDiscountFiled.cs    # Скидки
├── 20220511115703_addClientApiAcessField.cs # Доступ к API
├── 20220706074106_add-field-vink.cs         # Поля ВИНК
├── 20220817122146_addedNewFieldApiMonitoringTatneftSoapSuccessDateTime.cs
├── 20220914070050_addNewEntityReport.cs     # Отчеты
├── 20221107121504_addNewEntityVinkDiscount.cs # Скидки ВИНК
├── 20221129111212_newEntitiesForTemplatePlans.cs # Шаблоны планов
├── 20230307114407_addNewEntityForFuelTypeVinkForRouting.cs # Типы топлива для маршрутов
├── 20230412103811_CompanyEdo.cs             # ЭДО компаний
├── 20230601114953_addNewFieldIsVirtualForCard.cs # Виртуальные карты
├── 20230717103749_addNewFieldForHiddenCard.cs # Скрытые карты
├── 20230829081822_addNewEntityForRecalculateTransactionTask.cs # Пересчет транзакций
├── 20230927100021_addNewEntityTaskReport.cs  # Задачи отчетов
├── 20231122102639_modernCalculateBalanceAction.cs # Расчет баланса
├── 20240129043350_genitiveCaseFIOField.cs   # ФИО в родительном падеже
├── 20240216085739_avarageSumTwoWeekDailyPumping.cs # Средние чеки
├── 20240422081750_newFieldForTaskComment.cs # Комментарии задач
├── 20250304052942_addNewFieldForDCWVAPIURLLukoil.cs # URL Лукойл
├── 20250319064852_newEntityForViewDebt.cs    # Просмотр долгов
├── 20250423034937_newAccountReceivable.cs    # Дебиторская задолженность
├── 20250711081541_textForSBPQR.cs           # СБП QR
├── 20250716062058_calculateFTField.cs       # Расчет полей ФТ
├── 20250808051855_cardLogCardOwners.cs      # Логи владельцев карт
├── 20250917082606_cardResponseFromServer.cs # Ответы сервера карт
├── 20251014095826_addNewFieldForContractTermTemplate.cs # Поля шаблонов
├── 20251112083529_managementCardBlock.cs    # Блокировка карт менеджером
├── 20251112142207_superUserBlocked.cs       # Блокировка суперюзером
├── 20251217110845_addDirectContractOverdraftResetRequest.cs # Сброс овердрафта
├── 20251217124917_addNewFieldForTransaction.cs # Поля транзакций
├── 20251217131443_addFinanceTransactionVinkGasStationBrandSnapshot.cs # Снапшоты
├── 20251217133623_addNewFieldForGasStationTransaction.cs # Поля АЗС
├── 20251225130742_addDebtTextForModalLess15000.cs # Текст долга для модального окна
├── 20251226192006_newFieldsForCompanySettingsVAT.cs # НДС компаний
└── DataContextModelSnapshot.cs              # Снапшот модели

Ключевые миграции по хронологии

Период Миграции Основные изменения
2021-04 Initial, companyAndSeed, initCoreModels Создание базы, компании, пользователи
2021-04-05 cards, direactContracWithWink Карты, прямые договоры
2021-05 api settings, transactiontype API интеграция, типы транзакций
2021-06-07 GroupSync, payInfo, fuelTemplatePrice Синхронизация, оплаты, цены
2021-08-09 transactionUtc, partTimeUtc, checkBalanceVal UTC время, балансы
2021-11 addSystemDatas, ditributorFields, recoverPassword Системные данные, дистрибьюторы
2022-01-04 auto-input, directContractOverdraftInfo, AddMonitoringTransactions Автозаполнение, овердрафт
2022-04-08 addOffDiscountFiled, addLogCard, addClientApiAcessField Скидки, логи, API доступ
2022-08-09 addedNewFieldApiMonitoring, addNewEntityReport API мониторинг, отчеты
2022-11 addNewEntityVinkDiscount, newEntitiesForTemplatePlans Скидки ВИНК, шаблоны планов
2023-03-05 FuelTypeVinkForRouting, CompanyEdo, addNewFieldIsVirtualForCard Маршрутизация, ЭДО
2023-07-09 addNewEntityForRecalculateTransactionTask, modernCalculateBalanceAction Пересчет транзакций
2024-01-04 genitiveCaseFIOField, avarageSumTwoWeekDailyPumping, newFieldForTaskComment ФИО, статистика
2025-03-05 newAccountReceivable, calculateFTField, cardLogCardOwners Дебиторка, расчеты
2025-07-12 textForSBPQR, cardResponseFromServer СБП, ответы сервера
2025-11-12 managementCardBlock, superUserBlocked, addDirectContractOverdraftResetRequest Блокировки, сброс овердрафта
2025-12 addNewFieldForTransaction, addDebtTextForModalLess15000, newFieldsForCompanySettingsVAT Транзакции, долги, НДС

Управление миграциями

# Создание новой миграции
dotnet ef migrations add MigrationName --project FuelProcessing.Data

# Применение миграций
dotnet ef database update --project FuelProcessing.Data

# Откат к конкретной миграции
dotnet ef database update MigrationName --project FuelProcessing.Data

# Просмотр SQL для миграции
dotnet ef migrations script MigrationName --project FuelProcessing.Data

API клиенты ВИНК

IApiService — базовый интерфейс

Все 11 API клиентов реализуют общий интерфейс:

public interface IApiService
{
    bool IsTest { get; set; }
    void InitRestClient(DirectContractWithVendor settings, bool isTest = false);

    // Синхронизация
    List<Card> GetCards(int directContractWithVendorId);
    void GetTransactions();
    void GetGasStations();
    void GetBalance();

    // Управление
    List<SimpleRepeatItem> AddLimitsToCards(List<Limit> limit);
    void RestoreLimits(List<LimitVinkHistory> model);
    void BlockCard(CardBlockRepeat cardInfo);
    RepeatResultAnswer RepeatBlockCard(CardBlockRepeat cardInfo);

    // Запросы
    IEnumerable<ApiLimitInfo> GetLimits(string cardNumber);
    IEnumerable<FinanceTransaction> GetFinanceTransactionsByMounth(
        DirectContractWithVendor settings);
}

ApiExecutor — координатор

public class ApiExecutor
{
    public void Sync(VinkApiTypeSync typeSync)
    {
        // Автоматическая инициализация нужного API сервиса
        var apiService = _apiServiceFactory.Create(vinkType);

        // Выполнение с мониторингом
        ActionWithMonitoring(() =>
        {
            switch (typeSync)
            {
                case VinkApiTypeSync.Cards:
                    apiService.GetCards(contractId);
                    break;
                case VinkApiTypeSync.Balance:
                    apiService.GetBalance();
                    break;
                // ...
            }
        }, settings, typeSync);
    }
}

Типы синхронизации

public enum VinkApiTypeSync
{
    Cards,              // Синхронизация карт
    GasStations,        // Синхронизация АЗС
    HistoryTransactions, // Исторические транзакции
    Balance,            // Баланс договора
    AddLimitsToCards    // Установка лимитов
}

Бизнес-сервисы

FinancePartTransactionService

Основной сервис расчёта транзакций.

public class FinancePartTransactionService
{
    // Распределение транзакции по частям
    public async Task PartTransactions(FinanceTransaction transaction)

    // Установка ВИНК -> дистрибьютор
    private void SetVinkToVkrPart(FinanceTransaction transaction)

    // Установка дистрибьютор -> покупатель
    private void SetPart(FinanceTransaction transaction)

    // Установка для отрицательного баланса
    private void SetNegativePart(FinanceTransaction transaction)
}

BillingService

Сервис управления балансами.

public class BillingService
{
    // Получение баланса
    public async Task<decimal> GetBalanceAsync(int contractId)

    // Пополнение баланса
    public async Task ReplenishAsync(int contractId, decimal sum)

    // Списание
    public async Task WriteOffAsync(int contractId, decimal sum)

    // Установка временного овердрафта
    public async Task SetTempOverdraftAsync(int contractId,
        decimal sum, DateTime until)
}

Singletons

TransactionManager

Координатор операций обработки транзакций.

public class TransactionManager
{
    // Флаги состояния
    public bool IsSyncTransaction { get; set; }
    public bool IsRecalculateTransaction { get; set; }
    public bool IsCalculateBalance { get; set; }
    public bool IsReconciliationOfBalances { get; set; }
    public bool IsHourCheckBalance { get; set; }

    // Проверки возможности выполнения
    public bool CanCalculateBalance()
        => !IsReconciliationOfBalances && !IsHourCheckBalance;

    public bool CanRecalculateTransaction()
        => !IsReconciliationOfBalances;
}

Фоновые задачи (Workers)

Quartz Configuration

public class QuartzConfiguration
{
    public static void AddDSimpleIntervalJob<T>(
        string jobName,
        Func<ISimpleScheduleBuilder, ISimpleScheduleBuilder> schedule)
        where T : IJob
    {
        // Регистрация задачи с интервалом
    }
}

Расписание задач

Задача Интервал Назначение
FinanceTransactionCalculateJob 5 мин Расчёт транзакций
ApiJob (Cards) 2 часа Синхронизация карт
ApiJob (Balance) 20 мин Синхронизация балансов
BillingJob 08:00, 20:00 Сверка балансов

Коды ответов API

public enum ApiResponseCodes
{
    Success = 0,
    NoProxy = 1,
    Timeout = 2,
    NetworkError = 3,
    InvalidResponse = 4,
    MaxRetriesExceeded = 5,
    ServerError = 6
}

Связанная документация