Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/SmartTalk.Api/Controllers/PhoneOrderController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ await _mediator.SendAsync(new ReceivePhoneOrderRecordCommand {
return Ok();
}

[HttpPost("aixvolink/call-ended")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> ReceiveAixvolinkCallEndedAsync([FromBody] ReceiveAixvolinkPhoneOrderRecordCommand command)
{
await _mediator.SendAsync(command).ConfigureAwait(false);

return Ok();
}

[Route("manual/order"), HttpPost]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AddOrUpdateManualOrderResponse))]
public async Task<IActionResult> AddOrUpdateManualOrderAsync([FromBody] AddOrUpdateManualOrderCommand command)
Expand Down
4 changes: 4 additions & 0 deletions src/SmartTalk.Api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@
"BaseUrl": "",
"CompanyName": ""
},
"Daovika": {
"ApiKey": "",
"BaseUrl": ""
},
"SalesCustomerHabit": {
"ApiKey": "",
"BaseUrl": ""
Expand Down
6 changes: 6 additions & 0 deletions src/SmartTalk.Core/Constants/PhoneOrderSourceProviders.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace SmartTalk.Core.Constants;

public static class PhoneOrderSourceProviders
{
public const string Aixvolink = "AIXVOLINK";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE `phone_order_record`
ADD COLUMN `source_provider` VARCHAR(36) NULL AFTER `is_completed`;
5 changes: 4 additions & 1 deletion src/SmartTalk.Core/Domain/PhoneOrder/PhoneOrderRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,7 @@ public class PhoneOrderRecord : IEntity

[Column("is_completed")]
public bool IsCompleted { get; set; } = false;
}

[Column("source_provider"), StringLength(36)]
public string SourceProvider { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Mediator.Net.Context;
using Mediator.Net.Contracts;
using SmartTalk.Core.Constants;
using SmartTalk.Core.Services.Jobs;
using SmartTalk.Core.Services.PhoneOrder;
using SmartTalk.Messages.Commands.PhoneOrder;

namespace SmartTalk.Core.Handlers.CommandHandlers.PhoneOrder;

public class ReceiveAixvolinkPhoneOrderRecordCommandHandler : ICommandHandler<ReceiveAixvolinkPhoneOrderRecordCommand>
{
private readonly ISmartTalkBackgroundJobClient _backgroundJobClient;

public ReceiveAixvolinkPhoneOrderRecordCommandHandler(ISmartTalkBackgroundJobClient backgroundJobClient)
{
_backgroundJobClient = backgroundJobClient;
}

public Task Handle(IReceiveContext<ReceiveAixvolinkPhoneOrderRecordCommand> context, CancellationToken cancellationToken)
{
_backgroundJobClient.Enqueue<IPhoneOrderService>(x => x.ReceiveAixvolinkPhoneOrderRecordAsync(context.Message, cancellationToken), HangfireConstants.InternalHostingPhoneOrder);

return Task.CompletedTask;
}
}
62 changes: 39 additions & 23 deletions src/SmartTalk.Core/Services/Http/Clients/CrmClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text;
using Newtonsoft.Json;
using Serilog;
using SmartTalk.Core.Ioc;
using SmartTalk.Core.Settings.Crm;
using SmartTalk.Messages.Dto.AutoTest;
Expand All @@ -17,15 +18,17 @@ public interface ICrmClient : IScopedDependency

Task<List<GetCustomersPhoneNumberDataDto>> GetCustomersByPhoneNumberAsync(GetCustmoersByPhoneNumberRequestDto numberRequest, string token = null, CancellationToken cancellationToken = default);

Task<List<GetCustomerIdByShopNameResponseDto>> GetCustomerIdsByShopNameAsync(string shopName, CancellationToken cancellationToken = default);

Task<List<CrmContactDto>> GetCustomerContactsAsync(string customerId, string token = null, CancellationToken cancellationToken = default);

Task<List<GetDeliveryInfoByPhoneNumberResponseDto>> GetDeliveryInfoByPhoneNumberAsync(string phoneNumber, CancellationToken cancellationToken = default);
}

public class CrmClient : ICrmClient
{
private const string CustomerIdsByShopNamePath = "/api/external/get-customers-by-shop-name?shop_name={0}";
private readonly CrmSetting _crmSetting;
private readonly Dictionary<string, string> _headers;
private readonly ISmartTalkHttpClientFactory _httpClient;

public CrmClient(ISmartTalkHttpClientFactory httpClient, CrmSetting crmSetting)
Expand All @@ -44,9 +47,9 @@ public async Task<string> GetCrmTokenAsync(CancellationToken cancellationToken)
{ "client_id", _crmSetting.ClientId },
{ "client_secret", _crmSetting.ClientSecret }
};

var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");

var headers = new Dictionary<string, string>
{
{ "Accept", "application/json" }
Expand All @@ -57,38 +60,46 @@ public async Task<string> GetCrmTokenAsync(CancellationToken cancellationToken)
return response?.AccessToken;
}

public async Task<List<CrmContactDto>> GetCustomerContactsAsync(string customerId,
CancellationToken cancellationToken)
public Task<List<CrmContactDto>> GetCustomerContactsAsync(string customerId, CancellationToken cancellationToken)
{
return GetCustomerContactsAsync(customerId, token: null, cancellationToken);
}

public async Task<List<GetCustomersPhoneNumberDataDto>> GetCustomersByPhoneNumberAsync(GetCustmoersByPhoneNumberRequestDto numberRequest, string token = null, CancellationToken cancellationToken = default)
{
var token = await GetCrmTokenAsync(cancellationToken).ConfigureAwait(false);
token ??= await GetCrmTokenAsync(cancellationToken).ConfigureAwait(false);

var headers = new Dictionary<string, string>
{
{ "Accept", "application/json" },
{ "Authorization", $"Bearer {token}" }
{ "Authorization", $"Bearer {token}"}
};

return await _httpClient
.GetAsync<List<CrmContactDto>>($"{_crmSetting.BaseUrl}/api/customer/{customerId}/contacts",
headers: headers, cancellationToken: cancellationToken).ConfigureAwait(false);
var url = $"{_crmSetting.BaseUrl}/api/customer/get-customers-by-phone-number?phone_number={numberRequest.PhoneNumber}";

var result = await _httpClient.GetAsync<List<GetCustomersPhoneNumberDataDto>>(url, headers: headers, cancellationToken: cancellationToken).ConfigureAwait(false) ?? [];

Log.Information("Found {Count} customers for phone {PhoneNumber}", result.Count, numberRequest.PhoneNumber);
return result;
}


public async Task<List<GetCustomersPhoneNumberDataDto>> GetCustomersByPhoneNumberAsync(GetCustmoersByPhoneNumberRequestDto numberRequest, string token = null, CancellationToken cancellationToken = default)

public async Task<List<GetCustomerIdByShopNameResponseDto>> GetCustomerIdsByShopNameAsync(string shopName, CancellationToken cancellationToken = default)
{
token ??= await GetCrmTokenAsync(cancellationToken).ConfigureAwait(false);

if (string.IsNullOrWhiteSpace(shopName))
return [];

var headers = new Dictionary<string, string>
{
{ "Accept", "application/json" },
{ "Authorization", $"Bearer {token}"}
{ "X-API-KEY", _crmSetting.ApiKey }
};

var url = $"{_crmSetting.BaseUrl}/api/customer/get-customers-by-phone-number?phone_number={numberRequest.PhoneNumber}";

return await _httpClient
.GetAsync<List<GetCustomersPhoneNumberDataDto>>(url, headers: headers, cancellationToken: cancellationToken)
.ConfigureAwait(false);
var url = $"{_crmSetting.SyncBaseUrl}{string.Format(CustomerIdsByShopNamePath, Uri.EscapeDataString(shopName))}";

var result = await _httpClient.GetAsync<List<GetCustomerIdByShopNameResponseDto>>(url, headers: headers, cancellationToken: cancellationToken).ConfigureAwait(false) ?? [];

Log.Information("Found {Count} customer ids for shop {ShopName}", result.Count, shopName);
return result;
}

public async Task<List<AutoTestCallLogDto>> GetCallRecordsAsync(DateTime startTimeUtc, DateTime endTimeUtc, CancellationToken cancellationToken)
Expand Down Expand Up @@ -116,7 +127,12 @@ public async Task<List<CrmContactDto>> GetCustomerContactsAsync(string customerI
{ "Authorization", $"Bearer {token}" }
};

return await _httpClient.GetAsync<List<CrmContactDto>>($"{_crmSetting.BaseUrl}/api/customer/{customerId}/contacts", headers: headers, cancellationToken: cancellationToken).ConfigureAwait(false);
Log.Information("Fetching contacts for customer {CustomerId}", customerId);

var contacts = await _httpClient.GetAsync<List<CrmContactDto>>($"{_crmSetting.BaseUrl}/api/customer/{customerId}/contacts", headers: headers, cancellationToken: cancellationToken).ConfigureAwait(false) ?? [];
Log.Information("Found {Count} contacts for customer {CustomerId}", contacts.Count, customerId);

return contacts;
}

public async Task<List<GetDeliveryInfoByPhoneNumberResponseDto>> GetDeliveryInfoByPhoneNumberAsync(string phoneNumber, CancellationToken cancellationToken = default)
Expand All @@ -134,4 +150,4 @@ public async Task<List<GetDeliveryInfoByPhoneNumberResponseDto>> GetDeliveryInfo

return await _httpClient.GetAsync<List<GetDeliveryInfoByPhoneNumberResponseDto>>(url, cancellationToken: cancellationToken, headers: headers).ConfigureAwait(false);
}
}
}
48 changes: 48 additions & 0 deletions src/SmartTalk.Core/Services/Http/Clients/DaovikaClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using SmartTalk.Core.Ioc;
using SmartTalk.Core.Settings.Daovika;
using SmartTalk.Messages.Dto.Daovika;

namespace SmartTalk.Core.Services.Http.Clients;

public interface IDaovikaClient : IScopedDependency
{
Task<string> GetSalesGroupByPhoneNumberAsync(string phoneNumber, CancellationToken cancellationToken);
}

public class DaovikaClient : IDaovikaClient
{
private const string SalesGroupTableId = "fc7a74fc-ea1f-4be1-93c3-03ed190a2c56";

private readonly DaovikaSetting _daovikaSetting;
private readonly ISmartTalkHttpClientFactory _httpClientFactory;

public DaovikaClient(DaovikaSetting daovikaSetting, ISmartTalkHttpClientFactory httpClientFactory)
{
_daovikaSetting = daovikaSetting;
_httpClientFactory = httpClientFactory;
}

public async Task<string> GetSalesGroupByPhoneNumberAsync(string phoneNumber, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(phoneNumber))
return string.Empty;

var queryPhoneNumber = phoneNumber.Trim();
var url = $"{_daovikaSetting.BaseUrl}/api/external/table/query"
+ $"?tableId={SalesGroupTableId}"
+ $"&apiKey={Uri.EscapeDataString(_daovikaSetting.ApiKey)}"
+ "&field=phoneNumber&op=eq"
+ $"&value={Uri.EscapeDataString(queryPhoneNumber)}"
+ "&limit=1000&offset=0";

var headers = new Dictionary<string, string>
{
{ "accept", "application/json" },
{ "x-api-key", _daovikaSetting.ApiKey }
};

var response = await _httpClientFactory.GetAsync<GetSalesGroupByPhoneNumberResponseDto>(url, headers: headers, cancellationToken: cancellationToken).ConfigureAwait(false);

return response?.Rows?.FirstOrDefault()?.SalesGroup?.Trim() ?? string.Empty;
}
}
7 changes: 3 additions & 4 deletions src/SmartTalk.Core/Services/Http/Clients/SalesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,11 @@ public async Task<GetAskInfoDetailListByCustomerResponseDto> GetAskInfoDetailLis
{
if (request.CustomerNumbers == null || request.CustomerNumbers.Count == 0)
throw new ArgumentException("CustomerNumbers cannot be null or empty.");

var queryString = new StringBuilder("?");

foreach (var customerNumber in request.CustomerNumbers)
{
queryString.Append("CustomerNumbers=").Append(Uri.EscapeDataString(customerNumber)).Append('&');
}

var url = $"{_salesSetting.BaseUrl}/api/SalesOrder/GetAskInfoDetailListByCustomer" + queryString.ToString().TrimEnd('&');

Expand Down Expand Up @@ -126,4 +124,5 @@ public async Task<GetAiOrderItemsByDeliveryDateResponseDto> GetAiOrderItemsByDel

return await _httpClientFactory.GetAsync<GetAiOrderItemsByDeliveryDateResponseDto>(url, headers: _headers, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}

}
Loading