Try your search with a different keyword or use * as a wildcard.
@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').on('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').on('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" />