476 lines
25 KiB
Plaintext
476 lines
25 KiB
Plaintext
@model ConfigurationModel
|
|
|
|
@{
|
|
Layout = "_ConfigurePlugin";
|
|
NopHtml.SetActiveMenuItemSystemName(ZettleDefaults.SystemName);
|
|
|
|
var signUpUrl = $"https://my.zettle.com/apps/api-keys?name={ZettleDefaults.ApplicationName}&scopes=READ:FINANCE%20READ:PURCHASE%20READ:USERINFO%20READ:PRODUCT%20WRITE:PRODUCT&utm_source=local_partnership&utm_medium=ecommerce&utm_campaign=nopcommerce";
|
|
}
|
|
|
|
<form asp-controller="ZettleAdmin" asp-action="Configure" method="post" id="configuration-form">
|
|
<div class="cards-group">
|
|
<div class="card card-default no-margin">
|
|
|
|
<div class="card-header">
|
|
@T("Plugins.Misc.Zettle.Credentials")
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<p>
|
|
To enable this plugin, you'll need to:<br />
|
|
<br />
|
|
1. Go to your <a href="@signUpUrl" target="_blank">merchant account</a>.<br />
|
|
2. Review the information and click <b>Create key</b>. A client ID will be created together with the API key.<br />
|
|
3. On the <b>Create API key page</b>, click <b>Copy key</b> and paste it into the field on this plugin configuration page, do the same for Client ID.<br />
|
|
<em>Note: The API key will be displayed only once, so make sure to make a copy of it.</em><br />
|
|
</p>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<div class="label-wrapper">
|
|
<label class="col-form-label">
|
|
@T("Plugins.Misc.Zettle.Credentials.Status")
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="form-text-row">@T($"Plugins.Misc.Zettle.Credentials.{(Model.Connected ? "Connected" : "Disconnected")}")</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-9 offset-md-3">
|
|
@if (Model.Connected)
|
|
{
|
|
<button type="submit" name="revoke" class="btn btn-danger">@T("Plugins.Misc.Zettle.Credentials.Revoke")</button>
|
|
}
|
|
else
|
|
{
|
|
<a href="@signUpUrl" target="_blank" class="btn bg-olive">@T("Plugins.Misc.Zettle.Credentials.SignUp")</a>
|
|
}
|
|
</div>
|
|
</div>
|
|
@if (Model.Connected)
|
|
{
|
|
@if (!Model.Account.Accepted)
|
|
{
|
|
<div class="form-group row">
|
|
<div class="col-md-9 offset-md-3">
|
|
<div class="form-text-row">@T("Plugins.Misc.Zettle.Account.Pending", Model.Account.CustomerStatus, "https://www.zettle.com/gb/help/articles/1113715-confirm-your-identity")</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="Account.Name" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div class="form-text-row">@Model.Account.Name</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="Account.Currency" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div class="form-text-row">@Model.Account.Currency</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="Account.TaxationType" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div class="form-text-row">@Model.Account.TaxationType</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="Account.TaxationMode" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div class="form-text-row">@Model.Account.TaxationMode</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="ClientId" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="ClientId" />
|
|
<span asp-validation-for="ClientId"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="ApiKey" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="ApiKey" asp-required="@(!string.IsNullOrEmpty(Model.ClientId))" html-attributes="@(new { value = Model.ApiKey })" />
|
|
<span asp-validation-for="ApiKey"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="DisconnectOnUninstall" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="DisconnectOnUninstall" />
|
|
<span asp-validation-for="DisconnectOnUninstall"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-9 offset-md-3">
|
|
<button type="submit" name="credentials" class="btn btn-primary">@T("Admin.Common.Save")</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@if (Model.Connected)
|
|
{
|
|
<div class="card card-default no-margin">
|
|
<div class="card-header">
|
|
@T("Plugins.Misc.Zettle.Sync")
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<p>
|
|
The PayPal Zettle Go POS application will display product items that have been set up in the PayPal Zettle product library.<br />
|
|
Here you can define products from your nopCommerce catalog to be imported into PayPal Zettle product library and keep them synchronized across changes and updates.<br />
|
|
The product library consists of products and their variants (in nopCommerce they are product attribute combinations). For correct synchronization, you have to fill in SKUs for products and combinations.<br />
|
|
<br />
|
|
It's recommneded to keep the number of items in the product library below 10,000.<br />
|
|
<br />
|
|
You can only assign up to 99 variants (product attribute combinations) to a product. This means that you can specify a maximum of 3 product attributes for a product.<br />
|
|
If there are multiple product attributes, multiply the number of values of each attribute to get the total number of product variants.<br />
|
|
<em>For example, if you have 3 product attributes (Color, Size and Print) and the product attribute values for each attribute are 4 (Red, Blue, Green, Orange), 3 (9, 10, 11), and 2 (Animal, Floral) respectively, then the total number of product variants is 24 (4x3x2).</em><br />
|
|
<br />
|
|
Images are important parts of a product library. A product can have one single associated image.<br />
|
|
If you have enabled image synchronization, make sure that only ASCII characters are used in their names, the size must be smaller than 5 MB but bigger than 50*50 pixels.<br />
|
|
</p>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="AutoSyncEnabled" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="AutoSyncEnabled" />
|
|
<span asp-validation-for="AutoSyncEnabled"></span>
|
|
</div>
|
|
</div>
|
|
<nop-nested-setting asp-for="AutoSyncEnabled">
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="AutoSyncPeriod" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="AutoSyncPeriod" />
|
|
<span asp-validation-for="AutoSyncPeriod"></span>
|
|
</div>
|
|
</div>
|
|
</nop-nested-setting>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="DeleteBeforeImport" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="DeleteBeforeImport" />
|
|
<span asp-validation-for="DeleteBeforeImport"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="SyncEnabled" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="SyncEnabled" />
|
|
<span asp-validation-for="SyncEnabled"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="PriceSyncEnabled" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="PriceSyncEnabled" />
|
|
<span asp-validation-for="PriceSyncEnabled"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="ImageSyncEnabled" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="ImageSyncEnabled" />
|
|
<span asp-validation-for="ImageSyncEnabled"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="InventoryTrackingEnabled" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="InventoryTrackingEnabled" />
|
|
<span asp-validation-for="InventoryTrackingEnabled"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="DefaultTaxEnabled" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="DefaultTaxEnabled" />
|
|
<span asp-validation-for="DefaultTaxEnabled"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="DiscountSyncEnabled" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="DiscountSyncEnabled" />
|
|
<span asp-validation-for="DiscountSyncEnabled"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-9 offset-md-3">
|
|
<button type="submit" name="sync" class="btn btn-primary">@T("Admin.Common.Save")</button>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-12">
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit" id="add-record" onclick="javascript:OpenWindow('@(Url.Action("ProductToSync", "ZettleAdmin", new { btnId = "recordsUpdate", formId = "configuration-form" }))', 800, 800, true); return false;" class="btn bg-olive ml-1">
|
|
<i class="fas fa-square-plus"></i>
|
|
@T("Plugins.Misc.Zettle.Sync.AddProduct")
|
|
</button>
|
|
<button type="submit" id="recordsUpdate" style="display: none"></button>
|
|
|
|
<button type="button" id="delete-selected" class="btn btn-danger ml-1">
|
|
<i class="far fa-trash-can"></i>
|
|
@T("Plugins.Misc.Zettle.Sync.DeleteSelected")
|
|
</button>
|
|
<nop-action-confirmation asp-button-id="delete-selected" />
|
|
|
|
@await Html.PartialAsync("Table", new DataTablesModel
|
|
{
|
|
Name = "records-grid",
|
|
UrlRead = new DataUrl("SyncRecordList", "ZettleAdmin", null),
|
|
UrlUpdate = new DataUrl("SyncRecordUpdate", "ZettleAdmin", null),
|
|
Length = Model.SyncRecordSearchModel.PageSize,
|
|
LengthMenu = Model.SyncRecordSearchModel.AvailablePageSizes,
|
|
ColumnCollection = new List<ColumnProperty>
|
|
{
|
|
new ColumnProperty(nameof(SyncRecordModel.Id))
|
|
{
|
|
IsMasterCheckBox = true,
|
|
Render = new RenderCheckBox("records-checkbox"),
|
|
ClassName = NopColumnClassDefaults.CenterAll,
|
|
Width = "50",
|
|
},
|
|
new ColumnProperty(nameof(SyncRecordModel.ProductName))
|
|
{
|
|
Title = T("Plugins.Misc.Zettle.Sync.Fields.Product").Text,
|
|
Render = new RenderLink(new DataUrl("~/Admin/Product/Edit/", nameof(SyncRecordModel.ProductId)))
|
|
},
|
|
new ColumnProperty(nameof(SyncRecordModel.Active))
|
|
{
|
|
Title = T("Plugins.Misc.Zettle.Sync.Fields.Active").Text,
|
|
Width = "80",
|
|
ClassName = NopColumnClassDefaults.CenterAll,
|
|
Render = new RenderBoolean(),
|
|
Editable = true,
|
|
EditType = EditType.Checkbox
|
|
},
|
|
new ColumnProperty(nameof(SyncRecordModel.PriceSyncEnabled))
|
|
{
|
|
Title = T("Plugins.Misc.Zettle.Sync.Fields.PriceSyncEnabled").Text,
|
|
Width = "80",
|
|
ClassName = NopColumnClassDefaults.CenterAll,
|
|
Render = new RenderBoolean(),
|
|
Editable = true,
|
|
EditType = EditType.Checkbox
|
|
},
|
|
new ColumnProperty(nameof(SyncRecordModel.ImageSyncEnabled))
|
|
{
|
|
Title = T("Plugins.Misc.Zettle.Sync.Fields.ImageSyncEnabled").Text,
|
|
Width = "80",
|
|
ClassName = NopColumnClassDefaults.CenterAll,
|
|
Render = new RenderBoolean(),
|
|
Editable = true,
|
|
EditType = EditType.Checkbox
|
|
},
|
|
new ColumnProperty(nameof(SyncRecordModel.InventoryTrackingEnabled))
|
|
{
|
|
Title = T("Plugins.Misc.Zettle.Sync.Fields.InventoryTrackingEnabled").Text,
|
|
Width = "80",
|
|
ClassName = NopColumnClassDefaults.CenterAll,
|
|
Render = new RenderBoolean(),
|
|
Editable = true,
|
|
EditType = EditType.Checkbox
|
|
},
|
|
new ColumnProperty(nameof(SyncRecordModel.UpdatedDate))
|
|
{
|
|
Title = T("Plugins.Misc.Zettle.Sync.Fields.UpdatedDate").Text,
|
|
Width = "140",
|
|
Render = new RenderDate()
|
|
},
|
|
new ColumnProperty(nameof(SyncRecordModel.Id))
|
|
{
|
|
Title = T("Admin.Common.Edit").Text,
|
|
Width = "100",
|
|
ClassName = NopColumnClassDefaults.Button + " column-edit",
|
|
Render = new RenderButtonsInlineEdit()
|
|
}
|
|
}
|
|
})
|
|
|
|
<script>
|
|
$(function() {
|
|
$('#recordsUpdate').click(function () {
|
|
updateTable('#records-grid');
|
|
return false;
|
|
});
|
|
|
|
$('#start-sync-action-confirmation-submit-button').bind('click', function () {
|
|
$.ajax({
|
|
cache: false,
|
|
type: 'GET',
|
|
url: '@(Url.Action("SyncStart", "ZettleAdmin"))',
|
|
error: function (jqXHR, textStatus, errorThrown) {
|
|
showAlert('sync-failed', errorThrown);
|
|
},
|
|
complete: function (jqXHR, textStatus) {
|
|
window.location = window.location.href;
|
|
}
|
|
});
|
|
$('#start-sync-action-confirmation').modal('toggle');
|
|
return false;
|
|
});
|
|
|
|
$('#delete-selected-action-confirmation-submit-button').bind('click', function () {
|
|
var postData = {
|
|
selectedIds: selectedIds
|
|
};
|
|
addAntiForgeryToken(postData);
|
|
$.ajax({
|
|
cache: false,
|
|
type: 'POST',
|
|
url: '@(Url.Action("SyncRecordDelete", "ZettleAdmin"))',
|
|
data: postData,
|
|
traditional: true,
|
|
error: function (jqXHR, textStatus, errorThrown) {
|
|
showAlert('delete-selected-failed', errorThrown);
|
|
},
|
|
complete: function (jqXHR, textStatus) {
|
|
if (jqXHR.status === 204)
|
|
{
|
|
showAlert('nothing-selected-alert', '@T("Admin.Common.Alert.NothingSelected")');
|
|
return;
|
|
}
|
|
updateTable('#records-grid');
|
|
}
|
|
});
|
|
$('#delete-selected-action-confirmation').modal('toggle');
|
|
return false;
|
|
});
|
|
});
|
|
</script>
|
|
</div>
|
|
|
|
<div class="card-footer">
|
|
<button type="button" id="start-sync" class="btn btn-primary">
|
|
@T("Plugins.Misc.Zettle.Sync.Start")
|
|
</button>
|
|
<nop-action-confirmation asp-button-id="start-sync" asp-additional-confirm="Plugins.Misc.Zettle.Sync.Start.Confirm" />
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@if (!string.IsNullOrEmpty(Model.Import.State))
|
|
{
|
|
<div class="card card-default no-margin">
|
|
<div class="card-header">
|
|
@T("Plugins.Misc.Zettle.Sync.Last")
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="Import.StartDate" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div class="form-text-row" id="sync-start-date">@Model.Import.StartDate?.ToString("G")</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="Import.Items" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div class="form-text-row" id="sync-items">@Model.Import.Items</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="Import.State" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div class="form-text-row" id="sync-state">@Model.Import.State</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="Import.EndDate" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div class="form-text-row" id="sync-end-date">@Model.Import.EndDate?.ToString("G")</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@if (Model.Import.Active)
|
|
{
|
|
<script>
|
|
$(function() {
|
|
$('#start-sync').prop('disabled', true);
|
|
updateSyncState();
|
|
});
|
|
|
|
function updateSyncState() {
|
|
setTimeout(function () {
|
|
$.ajax({
|
|
cache: false,
|
|
type: 'GET',
|
|
url: '@(Url.Action("SyncUpdate", "ZettleAdmin"))',
|
|
success: function (data, textStatus, jqXHR) {
|
|
if (data.Completed) {
|
|
$('#start-sync').prop('disabled', false);
|
|
window.location = window.location.href;
|
|
}
|
|
else {
|
|
$('#sync-start-date').text(data.StartDate);
|
|
$('#sync-items').text(data.Items);
|
|
$('#sync-state').text(data.State);
|
|
updateSyncState();
|
|
}
|
|
},
|
|
error: function (jqXHR, textStatus, errorThrown) {
|
|
showAlert('sync-failed', errorThrown);
|
|
updateSyncState();
|
|
}
|
|
});
|
|
}, 10000);
|
|
}
|
|
</script>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</form>
|
|
|
|
<nop-alert asp-alert-id="delete-selected-failed" />
|
|
<nop-alert asp-alert-id="nothing-selected-alert" />
|
|
<nop-alert asp-alert-id="sync-failed" /> |