Tworzysz aplikację .NET 6. Napisz pełną implementację controller, service oraz wszystkich koniecznych do ich działania klas dla klasy FiscalPrinterPosnet.  Wzoruj się przy tym na plikach NfzContractController.cs oraz OccupationalFactorService.cs. Wygeneruj pełną treść plików.

/// FiscalPrinterPosnet.cs

using Abp.Domain.Entities.Auditing;
using Abp.Organizations;
using Abp.Domain.Entities;
using Medica.Helpers.Database;
using System;

namespace Medica.OrganizationUnits;

public class FiscalPrinterPosnet : FullAuditedEntity<Guid>, IMustHaveOrganizationUnit, IMustHaveTenant, INamedEntity, IPassivable
{
    public string Name { get; set; }

    public string Model { get; set; }

    public string IpAddress { get; set; }

    public string Port { get; set; }

    public bool IsActive { get; set; }

    public int TenantId { get; set; }

    public long OrganizationUnitId { get; set; }

    public virtual MedicaOrganizationUnit OrganizationUnit { get; set; }
}

/// NfzContractController.cs

#nullable enable

using System;
using System.Threading.Tasks;
using System.Xml;
using Abp.Application.Services.Dto;
using Abp.AspNetCore.Mvc.Controllers;
using Abp.Auditing;
using Abp.Authorization;
using Medica.Authorization;
using Medica.Extensions;
using Medica.Nfz.Contract;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace Medica.Nfz;

[AbpAuthorize(PermissionNames.NfzContracts_Manage, PermissionNames.NfzContracts_View)]
[Controller]
[Route("api/services/app/[controller]")]
public class NfzContractController : AbpController
{
    private readonly INfzContractService _nfzContractService;

    public NfzContractController(INfzContractService nfzContractService)
    {
        _nfzContractService = nfzContractService;
    }


    [DisableAuditing]
    [HttpPost(nameof(Search))]
    public Task<PagedResultDto<NfzContractDto>> Search([FromBody] NfzContractQueryDto dto) =>
        _nfzContractService.SearchAsync(dto.ToEntity()).MapPagedAsync(NfzContractConverters.ToNfzContractDto);
    
  
    [AbpAuthorize(PermissionNames.NfzContracts_Manage)]
    [HttpPut("{id:guid}")]
    public Task<NfzContractDto> Update([FromRoute] Guid id, [FromBody]NfzContractDto dto)
    {
        if (dto.Id != id) throw new Exception("Id mismatch");
        return _nfzContractService.UpdateAsync(NfzContractConverters.ToNfzContract(dto))
            .MapDtoAsync(NfzContractConverters.ToNfzContractDto);
    }

    [AbpAuthorize(PermissionNames.NfzContracts_Manage)]
    [HttpDelete("{id:guid}")]
    public Task DeleteFactorAsync([FromRoute] Guid id) => _nfzContractService.DeleteAsync(id).OrThrow();

    [HttpGet("{id:guid}")]
    public Task<NfzContractDto> GetAsync(Guid id) => _nfzContractService.GetAsync(id)
        .MapDtoAsync(NfzContractConverters.ToNfzContractDto);

    
    [AbpAuthorize(PermissionNames.NfzContracts_Manage)]
    [HttpPost]
    public async Task<NfzContractDto> Import(IFormCollection form)
    {
        var description = form["description"];
        
        if (form.Files?.FirstIfSingle() is not {} singleFile)
            throw new ArgumentException($"Expected single file. Found: {form.Files?.Count}");

        var xmlDoc = new XmlDocument();
        await using var stream = singleFile.OpenReadStream();
        xmlDoc.Load(stream);

        var importData = new NfzContractImportData(xmlDoc)
        {
            Description = description
        };
        
       var entity = await _nfzContractService.ImportAsync(importData).OrThrow();

       return NfzContractConverters.ToNfzContractDto(entity);
    }
}

/// OccupationalFactorService.cs

using System;
using System.Linq;
using System.Threading.Tasks;
using Medica.Commerce.OccupationalMedicine.Repository;
using Medica.Extensions;
using Medica.Helpers.Services;

namespace Medica.Commerce.OccupationalMedicine;

public class OccupationalFactorService : CrudService<Guid, OccupationalFactor, OccupationalFactorQuery>, IOccupationalFactorService
{
    private readonly IOccupationalFactorDbAdapter _occupationalFactorDbAdapter;

    public OccupationalFactorService(IOccupationalFactorDbAdapter dbAdapter) : base(dbAdapter)
    {
        _occupationalFactorDbAdapter = dbAdapter;
    }

    protected override void UpdateStaticFields(OccupationalFactor target, OccupationalFactor source)
    {
        target.Name = source.Name;
        target.Type = source.Type;
        target.Options = source.Options;
        target.SurveyName = source.SurveyName;
        target.StatementValiditySetup = source.StatementValiditySetup;
    }

    protected override Task<Either> ValidateDeleteRequest(Guid id)
    {
        return _occupationalFactorDbAdapter.GetWithSets(id).FlatMapAsync(entity =>
        {
            if (entity.Sets is not { Count: > 0 } sets) return Either.SuccessTask();
            return Either.UserFriendlyErrorTask($"Occupational factor is still assigned to sets: {sets.Select(v => v.Id).JoinAsStringWithLimit()}",
                $"Czynnik jest nadal przypisany do zbiorów: {sets.Select(v => v.Name).JoinAsStringWithLimit()}");
        });
    }
}

/// IOccupationalFactorService.cs

using System;
using Medica.Commerce.OccupationalMedicine.Repository;
using Medica.Helpers.Services;

namespace Medica.Commerce.OccupationalMedicine;

public interface IOccupationalFactorService : ICrudService<Guid, OccupationalFactor, OccupationalFactorQuery>
{

}