2020-05-23 21:13:18 +02:00
using System ;
2020-03-24 16:18:43 +01:00
using System.Collections.Generic ;
using System.Linq ;
2020-03-31 14:43:35 +02:00
using System.Threading.Tasks ;
2020-11-17 13:46:23 +01:00
using BTCPayServer.Abstractions.Constants ;
2024-07-11 02:28:24 +02:00
using BTCPayServer.Abstractions.Contracts ;
2022-02-24 09:00:44 +01:00
using BTCPayServer.Abstractions.Extensions ;
2024-11-07 02:43:22 +01:00
using BTCPayServer.Abstractions.Models ;
2020-03-31 10:47:13 +02:00
using BTCPayServer.Client ;
2020-04-01 08:21:54 +02:00
using BTCPayServer.Client.Models ;
2020-03-31 14:43:35 +02:00
using BTCPayServer.Data ;
2020-12-29 10:33:44 +01:00
using BTCPayServer.Payments ;
2024-07-11 02:28:24 +02:00
using BTCPayServer.Services ;
2023-01-23 13:51:00 +01:00
using BTCPayServer.Services.Rates ;
2020-03-31 14:43:35 +02:00
using BTCPayServer.Services.Stores ;
2020-03-24 16:18:43 +01:00
using Microsoft.AspNetCore.Authorization ;
2020-06-30 08:26:19 +02:00
using Microsoft.AspNetCore.Cors ;
2022-12-21 22:05:56 -08:00
using Microsoft.AspNetCore.Http ;
2020-03-31 14:43:35 +02:00
using Microsoft.AspNetCore.Identity ;
2020-03-24 16:18:43 +01:00
using Microsoft.AspNetCore.Mvc ;
2021-07-27 14:11:47 +02:00
using StoreData = BTCPayServer . Data . StoreData ;
2020-03-24 16:18:43 +01:00
2022-01-14 13:05:23 +09:00
namespace BTCPayServer.Controllers.Greenfield
2020-03-24 16:18:43 +01:00
{
[ApiController]
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
2020-06-30 08:26:19 +02:00
[EnableCors(CorsPolicies.All)]
2022-01-07 12:17:59 +09:00
public class GreenfieldStoresController : ControllerBase
2020-03-24 16:18:43 +01:00
{
2020-03-31 14:43:35 +02:00
private readonly StoreRepository _storeRepository ;
2024-10-04 22:24:44 +09:00
private readonly CurrencyNameTable _currencyNameTable ;
2020-03-31 14:43:35 +02:00
private readonly UserManager < ApplicationUser > _userManager ;
2024-07-11 02:28:24 +02:00
private readonly IFileService _fileService ;
private readonly UriResolver _uriResolver ;
2020-03-31 14:43:35 +02:00
2024-07-11 02:28:24 +02:00
public GreenfieldStoresController (
StoreRepository storeRepository ,
2024-10-04 22:24:44 +09:00
CurrencyNameTable currencyNameTable ,
2024-07-11 02:28:24 +02:00
UserManager < ApplicationUser > userManager ,
IFileService fileService ,
UriResolver uriResolver )
2020-03-31 14:43:35 +02:00
{
_storeRepository = storeRepository ;
2024-10-04 22:24:44 +09:00
_currencyNameTable = currencyNameTable ;
2020-03-31 14:43:35 +02:00
_userManager = userManager ;
2024-07-11 02:28:24 +02:00
_fileService = fileService ;
_uriResolver = uriResolver ;
2020-03-31 14:43:35 +02:00
}
2023-09-11 02:59:17 +02:00
2020-03-24 16:18:43 +01:00
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores")]
2024-07-11 02:28:24 +02:00
public async Task < ActionResult < IEnumerable < Client . Models . StoreData > > > GetStores ( )
2020-03-24 16:18:43 +01:00
{
2024-07-11 02:28:24 +02:00
var storesData = HttpContext . GetStoresData ( ) ;
var stores = new List < Client . Models . StoreData > ( ) ;
foreach ( var storeData in storesData )
{
stores . Add ( await FromModel ( storeData ) ) ;
}
return Ok ( stores ) ;
2020-03-24 16:18:43 +01:00
}
2020-06-28 17:55:27 +09:00
2020-03-31 10:47:13 +02:00
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpGet("~/api/v1/stores/{storeId}")]
2024-07-11 02:28:24 +02:00
public async Task < IActionResult > GetStore ( string storeId )
2020-03-31 10:47:13 +02:00
{
var store = HttpContext . GetStoreData ( ) ;
2024-07-11 02:28:24 +02:00
return store = = null ? StoreNotFound ( ) : Ok ( await FromModel ( store ) ) ;
2020-03-31 10:47:13 +02:00
}
2020-06-28 17:55:27 +09:00
2020-03-31 14:43:35 +02:00
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpDelete("~/api/v1/stores/{storeId}")]
2020-06-03 11:58:49 +02:00
public async Task < IActionResult > RemoveStore ( string storeId )
2020-03-31 14:43:35 +02:00
{
var store = HttpContext . GetStoreData ( ) ;
2024-07-11 02:28:24 +02:00
if ( store = = null ) return StoreNotFound ( ) ;
2020-03-31 14:43:35 +02:00
await _storeRepository . RemoveStore ( storeId , _userManager . GetUserId ( User ) ) ;
return Ok ( ) ;
}
2020-06-28 17:55:27 +09:00
2020-04-01 08:21:54 +02:00
[HttpPost("~/api/v1/stores")]
2020-06-27 15:34:03 +09:00
[Authorize(Policy = Policies.CanModifyStoreSettingsUnscoped, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
2020-04-30 16:43:16 +02:00
public async Task < IActionResult > CreateStore ( CreateStoreRequest request )
2020-04-01 08:21:54 +02:00
{
2020-04-30 16:43:16 +02:00
var validationResult = Validate ( request ) ;
2024-07-11 02:28:24 +02:00
if ( validationResult ! = null ) return validationResult ;
2021-12-31 16:59:02 +09:00
2024-07-11 02:28:24 +02:00
var store = new StoreData ( ) ;
2021-10-25 00:15:08 -04:00
PaymentMethodId . TryParse ( request . DefaultPaymentMethod , out var defaultPaymentMethodId ) ;
ToModel ( request , store , defaultPaymentMethodId ) ;
2020-04-30 16:43:16 +02:00
await _storeRepository . CreateStore ( _userManager . GetUserId ( User ) , store ) ;
2024-07-11 02:28:24 +02:00
return Ok ( await FromModel ( store ) ) ;
2020-04-01 08:21:54 +02:00
}
2020-06-28 17:55:27 +09:00
2020-04-27 13:13:20 +02:00
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpPut("~/api/v1/stores/{storeId}")]
2020-04-30 16:43:16 +02:00
public async Task < IActionResult > UpdateStore ( string storeId , UpdateStoreRequest request )
2020-04-27 13:13:20 +02:00
{
var store = HttpContext . GetStoreData ( ) ;
2024-07-11 02:28:24 +02:00
if ( store = = null ) return StoreNotFound ( ) ;
2020-04-30 16:43:16 +02:00
var validationResult = Validate ( request ) ;
2024-07-11 02:28:24 +02:00
if ( validationResult ! = null ) return validationResult ;
2020-04-27 13:13:20 +02:00
2021-10-25 00:15:08 -04:00
PaymentMethodId . TryParse ( request . DefaultPaymentMethod , out var defaultPaymentMethodId ) ;
ToModel ( request , store , defaultPaymentMethodId ) ;
2020-04-27 13:13:20 +02:00
await _storeRepository . UpdateStore ( store ) ;
2024-07-11 02:28:24 +02:00
return Ok ( await FromModel ( store ) ) ;
}
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpPost("~/api/v1/stores/{storeId}/logo")]
public async Task < IActionResult > UploadStoreLogo ( string storeId , IFormFile file )
{
2024-11-07 02:43:22 +01:00
var user = await _userManager . GetUserAsync ( User ) ;
2024-07-11 02:28:24 +02:00
var store = HttpContext . GetStoreData ( ) ;
2024-11-07 02:43:22 +01:00
if ( user = = null | | store = = null ) return StoreNotFound ( ) ;
UploadImageResultModel upload = null ;
2024-07-11 02:28:24 +02:00
if ( file is null )
ModelState . AddModelError ( nameof ( file ) , "Invalid file" ) ;
else
{
2024-11-07 02:43:22 +01:00
upload = await _fileService . UploadImage ( file , user . Id ) ;
if ( ! upload . Success )
ModelState . AddModelError ( nameof ( file ) , upload . Response ) ;
2024-07-11 02:28:24 +02:00
}
if ( ! ModelState . IsValid )
return this . CreateValidationError ( ModelState ) ;
2024-11-07 02:43:22 +01:00
2024-07-11 02:28:24 +02:00
try
{
2024-11-07 02:43:22 +01:00
var storedFile = upload ! . StoredFile ! ;
2024-07-11 02:28:24 +02:00
var blob = store . GetStoreBlob ( ) ;
blob . LogoUrl = new UnresolvedUri . FileIdUri ( storedFile . Id ) ;
store . SetStoreBlob ( blob ) ;
await _storeRepository . UpdateStore ( store ) ;
return Ok ( await FromModel ( store ) ) ;
}
catch ( Exception e )
{
return this . CreateAPIError ( 404 , "file-upload-failed" , e . Message ) ;
}
}
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpDelete("~/api/v1/stores/{storeId}/logo")]
public async Task < IActionResult > DeleteStoreLogo ( string storeId )
{
var store = HttpContext . GetStoreData ( ) ;
if ( store = = null ) return StoreNotFound ( ) ;
var blob = store . GetStoreBlob ( ) ;
var fileId = ( blob . LogoUrl as UnresolvedUri . FileIdUri ) ? . FileId ;
if ( ! string . IsNullOrEmpty ( fileId ) )
{
var userId = _userManager . GetUserId ( User ) ! ;
await _fileService . RemoveFile ( fileId , userId ) ;
blob . LogoUrl = null ;
store . SetStoreBlob ( blob ) ;
await _storeRepository . UpdateStore ( store ) ;
}
return Ok ( ) ;
2020-04-27 13:13:20 +02:00
}
2020-04-01 08:21:54 +02:00
2024-07-11 02:28:24 +02:00
internal async Task < Client . Models . StoreData > FromModel ( StoreData data )
2020-03-24 16:18:43 +01:00
{
2020-05-23 21:13:18 +02:00
var storeBlob = data . GetStoreBlob ( ) ;
2023-05-11 10:38:40 +02:00
return new Client . Models . StoreData
2020-03-24 16:18:43 +01:00
{
2020-06-28 17:55:27 +09:00
Id = data . Id ,
2020-05-23 21:13:18 +02:00
Name = data . StoreName ,
Website = data . StoreWebsite ,
2023-09-11 02:59:17 +02:00
Archived = data . Archived ,
2024-05-09 02:18:02 +02:00
BrandColor = storeBlob . BrandColor ,
2024-09-13 14:39:21 +02:00
ApplyBrandColorToBackend = storeBlob . ApplyBrandColorToBackend ,
2024-07-11 02:28:24 +02:00
CssUrl = storeBlob . CssUrl = = null ? null : await _uriResolver . Resolve ( Request . GetAbsoluteRootUri ( ) , storeBlob . CssUrl ) ,
LogoUrl = storeBlob . LogoUrl = = null ? null : await _uriResolver . Resolve ( Request . GetAbsoluteRootUri ( ) , storeBlob . LogoUrl ) ,
PaymentSoundUrl = storeBlob . PaymentSoundUrl = = null ? null : await _uriResolver . Resolve ( Request . GetAbsoluteRootUri ( ) , storeBlob . PaymentSoundUrl ) ,
2023-05-11 10:38:40 +02:00
SupportUrl = storeBlob . StoreSupportUrl ,
2020-05-23 21:13:18 +02:00
SpeedPolicy = data . SpeedPolicy ,
2024-04-04 16:31:04 +09:00
DefaultPaymentMethod = data . GetDefaultPaymentId ( ) ? . ToString ( ) ,
2020-05-23 21:13:18 +02:00
//blob
//we do not include DefaultCurrencyPairs,Spread, PreferredExchange, RateScripting, RateScript in this model and instead opt to set it in stores/storeid/rates endpoints
//we do not include ExcludedPaymentMethods in this model and instead opt to set it in stores/storeid/payment-methods endpoints
//we do not include EmailSettings in this model and instead opt to set it in stores/storeid/email endpoints
2020-12-29 10:33:44 +01:00
//we do not include PaymentMethodCriteria because moving the CurrencyValueJsonConverter to the Client csproj is hard and requires a refactor (#1571 & #1572)
2020-05-23 21:13:18 +02:00
NetworkFeeMode = storeBlob . NetworkFeeMode ,
2023-06-27 11:39:30 +02:00
DefaultCurrency = storeBlob . DefaultCurrency ,
2022-07-06 14:14:55 +02:00
Receipt = InvoiceDataBase . ReceiptOptions . Merge ( storeBlob . ReceiptOptions , null ) ,
2020-11-09 01:11:03 -06:00
LightningAmountInSatoshi = storeBlob . LightningAmountInSatoshi ,
LightningPrivateRouteHints = storeBlob . LightningPrivateRouteHints ,
OnChainWithLnInvoiceFallback = storeBlob . OnChainWithLnInvoiceFallback ,
RedirectAutomatically = storeBlob . RedirectAutomatically ,
2021-04-07 06:08:42 +02:00
LazyPaymentMethods = storeBlob . LazyPaymentMethods ,
2020-05-23 21:13:18 +02:00
ShowRecommendedFee = storeBlob . ShowRecommendedFee ,
RecommendedFeeBlockTarget = storeBlob . RecommendedFeeBlockTarget ,
DefaultLang = storeBlob . DefaultLang ,
2020-08-26 14:01:39 +09:00
MonitoringExpiration = storeBlob . MonitoringExpiration ,
InvoiceExpiration = storeBlob . InvoiceExpiration ,
2023-01-16 12:45:19 +01:00
DisplayExpirationTimer = storeBlob . DisplayExpirationTimer ,
2020-05-23 21:13:18 +02:00
HtmlTitle = storeBlob . HtmlTitle ,
2020-05-31 11:42:49 +09:00
AnyoneCanCreateInvoice = storeBlob . AnyoneCanInvoice ,
2020-05-23 21:13:18 +02:00
LightningDescriptionTemplate = storeBlob . LightningDescriptionTemplate ,
PaymentTolerance = storeBlob . PaymentTolerance ,
2023-01-23 13:51:00 +01:00
PayJoinEnabled = storeBlob . PayJoinEnabled ,
2023-10-18 12:20:05 +02:00
AutoDetectLanguage = storeBlob . AutoDetectLanguage ,
ShowPayInWalletButton = storeBlob . ShowPayInWalletButton ,
ShowStoreHeader = storeBlob . ShowStoreHeader ,
CelebratePayment = storeBlob . CelebratePayment ,
PlaySoundOnPayment = storeBlob . PlaySoundOnPayment ,
PaymentMethodCriteria = storeBlob . PaymentMethodCriteria ? . Where ( criteria = > criteria . Value is not null ) . Select ( criteria = > new PaymentMethodCriteriaData
2023-01-23 13:51:00 +01:00
{
Above = criteria . Above ,
Amount = criteria . Value . Value ,
CurrencyCode = criteria . Value . Currency ,
2024-09-06 13:24:33 +09:00
PaymentMethodId = criteria . PaymentMethod . ToString ( )
2023-10-18 12:20:05 +02:00
} ) . ToList ( ) ? ? new List < PaymentMethodCriteriaData > ( )
2020-03-24 16:18:43 +01:00
} ;
}
2020-05-23 21:13:18 +02:00
2023-01-23 13:51:00 +01:00
private void ToModel ( StoreBaseData restModel , StoreData model , PaymentMethodId defaultPaymentMethod )
2020-04-22 14:42:30 +02:00
{
2020-05-23 21:13:18 +02:00
var blob = model . GetStoreBlob ( ) ;
model . StoreName = restModel . Name ;
model . StoreWebsite = restModel . Website ;
2023-09-11 02:59:17 +02:00
model . Archived = restModel . Archived ;
2020-05-23 21:13:18 +02:00
model . SpeedPolicy = restModel . SpeedPolicy ;
2020-12-29 10:33:44 +01:00
model . SetDefaultPaymentId ( defaultPaymentMethod ) ;
2020-05-23 21:13:18 +02:00
//we do not include the default payment method in this model and instead opt to set it in the stores/storeid/payment-methods endpoints
//blob
//we do not include DefaultCurrencyPairs;Spread; PreferredExchange; RateScripting; RateScript in this model and instead opt to set it in stores/storeid/rates endpoints
//we do not include ExcludedPaymentMethods in this model and instead opt to set it in stores/storeid/payment-methods endpoints
//we do not include EmailSettings in this model and instead opt to set it in stores/storeid/email endpoints
//we do not include OnChainMinValue and LightningMaxValue because moving the CurrencyValueJsonConverter to the Client csproj is hard and requires a refactor (#1571 & #1572)
blob . NetworkFeeMode = restModel . NetworkFeeMode ;
2021-10-20 23:17:40 +09:00
blob . DefaultCurrency = restModel . DefaultCurrency ;
2022-07-06 14:14:55 +02:00
blob . ReceiptOptions = InvoiceDataBase . ReceiptOptions . Merge ( restModel . Receipt , null ) ;
2020-11-09 01:11:03 -06:00
blob . LightningAmountInSatoshi = restModel . LightningAmountInSatoshi ;
blob . LightningPrivateRouteHints = restModel . LightningPrivateRouteHints ;
blob . OnChainWithLnInvoiceFallback = restModel . OnChainWithLnInvoiceFallback ;
2021-04-07 06:08:42 +02:00
blob . LazyPaymentMethods = restModel . LazyPaymentMethods ;
2020-11-09 01:11:03 -06:00
blob . RedirectAutomatically = restModel . RedirectAutomatically ;
2020-05-23 21:13:18 +02:00
blob . ShowRecommendedFee = restModel . ShowRecommendedFee ;
blob . RecommendedFeeBlockTarget = restModel . RecommendedFeeBlockTarget ;
blob . DefaultLang = restModel . DefaultLang ;
2023-05-11 10:38:40 +02:00
blob . StoreSupportUrl = restModel . SupportUrl ;
2020-08-26 14:01:39 +09:00
blob . MonitoringExpiration = restModel . MonitoringExpiration ;
blob . InvoiceExpiration = restModel . InvoiceExpiration ;
2023-01-16 12:45:19 +01:00
blob . DisplayExpirationTimer = restModel . DisplayExpirationTimer ;
2020-05-23 21:13:18 +02:00
blob . HtmlTitle = restModel . HtmlTitle ;
2020-05-31 11:42:49 +09:00
blob . AnyoneCanInvoice = restModel . AnyoneCanCreateInvoice ;
2020-05-23 21:13:18 +02:00
blob . LightningDescriptionTemplate = restModel . LightningDescriptionTemplate ;
blob . PaymentTolerance = restModel . PaymentTolerance ;
blob . PayJoinEnabled = restModel . PayJoinEnabled ;
2024-05-09 02:18:02 +02:00
blob . BrandColor = restModel . BrandColor ;
2024-09-13 14:39:21 +02:00
blob . ApplyBrandColorToBackend = restModel . ApplyBrandColorToBackend ;
2024-05-09 02:18:02 +02:00
blob . LogoUrl = restModel . LogoUrl is null ? null : UnresolvedUri . Create ( restModel . LogoUrl ) ;
blob . CssUrl = restModel . CssUrl is null ? null : UnresolvedUri . Create ( restModel . CssUrl ) ;
blob . PaymentSoundUrl = restModel . PaymentSoundUrl is null ? null : UnresolvedUri . Create ( restModel . PaymentSoundUrl ) ;
2023-10-18 12:20:05 +02:00
if ( restModel . AutoDetectLanguage . HasValue )
blob . AutoDetectLanguage = restModel . AutoDetectLanguage . Value ;
if ( restModel . ShowPayInWalletButton . HasValue )
blob . ShowPayInWalletButton = restModel . ShowPayInWalletButton . Value ;
if ( restModel . ShowStoreHeader . HasValue )
blob . ShowStoreHeader = restModel . ShowStoreHeader . Value ;
if ( restModel . CelebratePayment . HasValue )
blob . CelebratePayment = restModel . CelebratePayment . Value ;
if ( restModel . PlaySoundOnPayment . HasValue )
blob . PlaySoundOnPayment = restModel . PlaySoundOnPayment . Value ;
2023-01-23 13:51:00 +01:00
blob . PaymentMethodCriteria = restModel . PaymentMethodCriteria ? . Select ( criteria = >
2023-10-18 12:20:05 +02:00
new PaymentMethodCriteria
2023-01-23 13:51:00 +01:00
{
Above = criteria . Above ,
2023-10-18 12:20:05 +02:00
Value = new CurrencyValue
2023-01-23 13:51:00 +01:00
{
Currency = criteria . CurrencyCode ,
Value = criteria . Amount
} ,
2024-09-06 13:24:33 +09:00
PaymentMethod = PaymentMethodId . Parse ( criteria . PaymentMethodId )
2023-01-23 13:51:00 +01:00
} ) . ToList ( ) ? ? new List < PaymentMethodCriteria > ( ) ;
2020-05-23 21:13:18 +02:00
model . SetStoreBlob ( blob ) ;
2020-04-30 16:43:16 +02:00
}
private IActionResult Validate ( StoreBaseData request )
{
2020-05-23 21:13:18 +02:00
if ( request is null )
{
return BadRequest ( ) ;
}
2020-06-28 17:55:27 +09:00
2020-12-29 10:33:44 +01:00
if ( ! string . IsNullOrEmpty ( request . DefaultPaymentMethod ) & &
2024-01-18 09:47:39 +09:00
! PaymentMethodId . TryParse ( request . DefaultPaymentMethod , out _ ) )
2020-12-29 10:33:44 +01:00
{
ModelState . AddModelError ( nameof ( request . Name ) , "DefaultPaymentMethod is invalid" ) ;
}
2021-12-31 16:59:02 +09:00
2020-05-23 21:13:18 +02:00
if ( string . IsNullOrEmpty ( request . Name ) )
2020-04-30 16:43:16 +02:00
ModelState . AddModelError ( nameof ( request . Name ) , "Name is missing" ) ;
2020-06-28 17:55:27 +09:00
else if ( request . Name . Length < 1 | | request . Name . Length > 50 )
2020-05-23 21:13:18 +02:00
ModelState . AddModelError ( nameof ( request . Name ) , "Name can only be between 1 and 50 characters" ) ;
if ( ! string . IsNullOrEmpty ( request . Website ) & & ! Uri . TryCreate ( request . Website , UriKind . Absolute , out _ ) )
{
ModelState . AddModelError ( nameof ( request . Website ) , "Website is not a valid url" ) ;
}
2024-05-09 02:18:02 +02:00
if ( ! string . IsNullOrEmpty ( request . LogoUrl ) & & ! Uri . TryCreate ( request . LogoUrl , UriKind . Absolute , out _ ) )
{
ModelState . AddModelError ( nameof ( request . LogoUrl ) , "Logo is not a valid url" ) ;
}
if ( ! string . IsNullOrEmpty ( request . CssUrl ) & & ! Uri . TryCreate ( request . CssUrl , UriKind . Absolute , out _ ) )
{
ModelState . AddModelError ( nameof ( request . CssUrl ) , "CSS is not a valid url" ) ;
}
if ( ! string . IsNullOrEmpty ( request . BrandColor ) & & ! ColorPalette . IsValid ( request . BrandColor ) )
{
ModelState . AddModelError ( nameof ( request . BrandColor ) , "Brand color is not a valid HEX Color (e.g. #F7931A)" ) ;
}
2020-06-28 17:55:27 +09:00
if ( request . InvoiceExpiration < TimeSpan . FromMinutes ( 1 ) & & request . InvoiceExpiration > TimeSpan . FromMinutes ( 60 * 24 * 24 ) )
2020-05-23 21:13:18 +02:00
ModelState . AddModelError ( nameof ( request . InvoiceExpiration ) , "InvoiceExpiration can only be between 1 and 34560 mins" ) ;
2023-01-16 12:45:19 +01:00
if ( request . DisplayExpirationTimer < TimeSpan . FromMinutes ( 1 ) & & request . DisplayExpirationTimer > TimeSpan . FromMinutes ( 60 * 24 * 24 ) )
ModelState . AddModelError ( nameof ( request . DisplayExpirationTimer ) , "DisplayExpirationTimer can only be between 1 and 34560 mins" ) ;
2020-06-28 17:55:27 +09:00
if ( request . MonitoringExpiration < TimeSpan . FromMinutes ( 10 ) & & request . MonitoringExpiration > TimeSpan . FromMinutes ( 60 * 24 * 24 ) )
2023-01-16 12:45:19 +01:00
ModelState . AddModelError ( nameof ( request . MonitoringExpiration ) , "MonitoringExpiration can only be between 10 and 34560 mins" ) ;
2023-05-19 08:41:21 +09:00
if ( request . PaymentTolerance < 0 | | request . PaymentTolerance > 100 )
2020-05-23 21:13:18 +02:00
ModelState . AddModelError ( nameof ( request . PaymentTolerance ) , "PaymentTolerance can only be between 0 and 100 percent" ) ;
2020-06-03 11:58:49 +02:00
2023-01-23 13:51:00 +01:00
if ( request . PaymentMethodCriteria ? . Any ( ) is true )
{
for ( int index = 0 ; index < request . PaymentMethodCriteria . Count ; index + + )
{
PaymentMethodCriteriaData pmc = request . PaymentMethodCriteria [ index ] ;
if ( string . IsNullOrEmpty ( pmc . CurrencyCode ) )
{
request . AddModelError ( data = > data . PaymentMethodCriteria [ index ] . CurrencyCode , "CurrencyCode is required" , this ) ;
2023-04-10 11:07:03 +09:00
}
2024-10-04 22:24:44 +09:00
else if ( _currencyNameTable . GetCurrencyData ( pmc . CurrencyCode , false ) is null )
2023-01-23 13:51:00 +01:00
{
request . AddModelError ( data = > data . PaymentMethodCriteria [ index ] . CurrencyCode , "CurrencyCode is invalid" , this ) ;
}
2024-09-06 13:24:33 +09:00
if ( string . IsNullOrEmpty ( pmc . PaymentMethodId ) | | PaymentMethodId . TryParse ( pmc . PaymentMethodId ) is null )
2023-01-23 13:51:00 +01:00
{
2024-09-06 13:24:33 +09:00
request . AddModelError ( data = > data . PaymentMethodCriteria [ index ] . PaymentMethodId , "Payment method was invalid" , this ) ;
2023-01-23 13:51:00 +01:00
}
if ( pmc . Amount < 0 )
{
request . AddModelError ( data = > data . PaymentMethodCriteria [ index ] . Amount , "Amount must be greater than 0" , this ) ;
}
}
}
2020-06-08 23:40:58 +09:00
return ! ModelState . IsValid ? this . CreateValidationError ( ModelState ) : null ;
2020-04-22 14:42:30 +02:00
}
2021-12-31 16:59:02 +09:00
2021-12-23 05:32:08 +01:00
private IActionResult StoreNotFound ( )
{
return this . CreateAPIError ( 404 , "store-not-found" , "The store was not found" ) ;
}
2020-03-24 16:18:43 +01:00
}
}