diff --git a/.gitignore b/.gitignore index 93569d6683a..44d33b8262c 100644 --- a/.gitignore +++ b/.gitignore @@ -110,3 +110,6 @@ local-builds.gradle # gitignore for retrocompatibility, so that it won't appear as a new file and # be accidentally checked in the repository. google-upload-credentials.json + +# Kotlin +.kotlin/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 4796b2713dc..6cfa071d0a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ +## 21.1 +Our latest update brings key enhancements to streamline your WooCommerce experience! We’ve fixed editing permissions for orders in different currencies, optimized the payments hub view, enabled easy receipt sharing via Google SMS, and fixed date range selection to correctly use your timezone. Enjoy smoother operations! + ## 21.0 Enjoy a smoother experience with improved design throughout the app. Plus, now your product images load faster and look even better with new AVIF format support. Update now for a cleaner, sharper WooCommerce app experience! diff --git a/Gemfile b/Gemfile index 74097a6ca89..abf3d9c2fa1 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' -gem 'danger-dangermattic', '~> 1.1' +gem 'danger-dangermattic', '~> 1.2' gem 'fastlane', '~> 2.216' gem 'nokogiri' gem 'rubocop', '~> 1.65' diff --git a/Gemfile.lock b/Gemfile.lock index 5e4ebbe1c33..1dfa7a38c68 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -23,7 +23,7 @@ GEM ast (2.4.2) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.999.0) + aws-partitions (1.1001.0) aws-sdk-core (3.211.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) @@ -72,7 +72,7 @@ GEM octokit (>= 4.0) pstore (~> 0.1) terminal-table (>= 1, < 4) - danger-dangermattic (1.1.2) + danger-dangermattic (1.2.1) danger (~> 9.4) danger-plugin-api (~> 1.0) danger-rubocop (~> 0.13) @@ -231,7 +231,7 @@ GEM concurrent-ruby (~> 1.0) java-properties (0.3.0) jmespath (1.6.2) - json (2.7.5) + json (2.7.6) jwt (2.9.3) base64 kramdown (2.4.0) @@ -242,7 +242,6 @@ GEM logger (1.6.1) mini_magick (4.13.2) mini_mime (1.1.5) - mini_portile2 (2.8.7) minitest (5.25.1) multi_json (1.15.0) multipart-post (2.4.1) @@ -250,8 +249,17 @@ GEM nap (1.1.0) naturally (2.2.1) nkf (0.2.0) - nokogiri (1.16.7) - mini_portile2 (~> 2.8.2) + nokogiri (1.16.7-aarch64-linux) + racc (~> 1.4) + nokogiri (1.16.7-arm-linux) + racc (~> 1.4) + nokogiri (1.16.7-arm64-darwin) + racc (~> 1.4) + nokogiri (1.16.7-x86-linux) + racc (~> 1.4) + nokogiri (1.16.7-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) octokit (6.1.1) faraday (>= 1, < 3) @@ -261,7 +269,7 @@ GEM optparse (0.5.0) os (1.1.4) parallel (1.26.3) - parser (3.3.5.0) + parser (3.3.6.0) ast (~> 2.4.1) racc plist (3.7.1) @@ -295,7 +303,7 @@ GEM rubocop-ast (>= 1.32.2, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.33.0) + rubocop-ast (1.34.0) parser (>= 3.3.1.0) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) @@ -340,10 +348,16 @@ GEM xcpretty (~> 0.2, >= 0.0.7) PLATFORMS + aarch64-linux + arm-linux + arm64-darwin ruby + x86-linux + x86_64-darwin + x86_64-linux DEPENDENCIES - danger-dangermattic (~> 1.1) + danger-dangermattic (~> 1.2) fastlane (~> 2.216) fastlane-plugin-wpmreleasetoolkit (~> 12.3) nokogiri @@ -351,4 +365,4 @@ DEPENDENCIES rubocop (~> 1.65) BUNDLED WITH - 2.4.19 + 2.5.20 diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index fa7d018f570..a0373887201 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -3,11 +3,17 @@ *** For entries which are touching the Android Wear app's, start entry with `[WEAR]` too. 21.2 - [Internal] Changed a way how authenticated web view opened in the IPP flows [https://github.com/woocommerce/woocommerce-android/pull/12908] +----- +- [**][Payments] Fixed a bug when IPP onboarding was not possible to finish from the app [https://github.com/woocommerce/woocommerce-android/pull/12917] +- [*] Fixed shipping lines being editable at all states [https://github.com/woocommerce/woocommerce-android/pull/12890] +- [*] Fixed a crash that occurred when tapping on the customer shipping address in the order details screen [https://github.com/woocommerce/woocommerce-android/pull/12920] 21.1 ----- +- [*] Disable Edit option for orders whose currency does not match with store currency [https://github.com/woocommerce/woocommerce-android/pull/12880] - [*] Show web views on the payments hub screen in 3/4 of the screen [https://github.com/woocommerce/woocommerce-android/pull/12875] - [*] Receipts can be shared via a google's sms application now [https://github.com/woocommerce/woocommerce-android/pull/12874] +- [*] Fixed a bug where picking date ranges (for Stats and Analytics) did not use the correct timezone [https://github.com/woocommerce/woocommerce-android/pull/12887] 21.0 ----- diff --git a/WooCommerce-Wear/build.gradle b/WooCommerce-Wear/build.gradle index b82c097ea5a..b7b4296340b 100644 --- a/WooCommerce-Wear/build.gradle +++ b/WooCommerce-Wear/build.gradle @@ -3,6 +3,7 @@ import io.sentry.android.gradle.extensions.InstrumentationFeature plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) alias(libs.plugins.kotlin.parcelize) alias(libs.plugins.google.dagger.hilt) alias(libs.plugins.ksp) @@ -77,19 +78,13 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' + sourceCompatibility libs.versions.java.get() + targetCompatibility libs.versions.java.get() } buildFeatures { buildConfig true compose true } - composeOptions { - kotlinCompilerExtensionVersion libs.versions.androidx.compose.compiler.get() - } packaging { resources { excludes += '/META-INF/{AL2.0,LGPL2.1}' diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index e0d799593dc..418c353d77d 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -3,6 +3,7 @@ import io.sentry.android.gradle.extensions.InstrumentationFeature plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) alias(libs.plugins.kotlin.parcelize) alias(libs.plugins.google.dagger.hilt) alias(libs.plugins.sentry) @@ -145,15 +146,11 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility libs.versions.java.get() + targetCompatibility libs.versions.java.get() coreLibraryDesugaringEnabled true } - composeOptions { - kotlinCompilerExtensionVersion libs.versions.androidx.compose.compiler.get() - } - flavorDimensions "buildType" productFlavors { diff --git a/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/2787/2787_connect_label.json b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/2787/2787_connect_label.json new file mode 100644 index 00000000000..3f7d9a62f31 --- /dev/null +++ b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/2787/2787_connect_label.json @@ -0,0 +1,24 @@ +{ + "request": { + "method": "GET", + "urlPathPattern": "/rest/v1.1/jetpack-blogs/161477129/rest-api/", + "queryParameters": { + "json": { + "equalTo": "true" + }, + "path": { + "matches": "/wc/v1/connect/label/2787(.*)" + } + } + }, + "response": { + "status": 200, + "jsonBody": { + "data": {} + }, + "headers": { + "Content-Type": "application/json", + "Connection": "keep-alive" + } + } +} diff --git a/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/2787/2787_refunds.json b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/2787/2787_refunds.json new file mode 100644 index 00000000000..ee17a6a9c2f --- /dev/null +++ b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/2787/2787_refunds.json @@ -0,0 +1,24 @@ +{ + "request": { + "method": "GET", + "urlPathPattern": "/rest/v1.1/jetpack-blogs/161477129/rest-api/", + "queryParameters": { + "json": { + "equalTo": "true" + }, + "path": { + "matches": "/wc/v3/orders/2787/refunds(.*)" + } + } + }, + "response": { + "status": 200, + "jsonBody": { + "data": [] + }, + "headers": { + "Content-Type": "application/json", + "Connection": "keep-alive" + } + } +} diff --git a/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/2787/2787_shipping_methods.json b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/2787/2787_shipping_methods.json new file mode 100644 index 00000000000..d74ce30b6b0 --- /dev/null +++ b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/2787/2787_shipping_methods.json @@ -0,0 +1,24 @@ +{ + "request": { + "method": "GET", + "urlPathPattern": "/rest/v1.1/jetpack-blogs/161477129/rest-api/", + "queryParameters": { + "json": { + "equalTo": "true" + }, + "path": { + "equalTo": "/wc/v3/shipping_methods/&_method=get" + } + } + }, + "response": { + "status": 200, + "jsonBody": { + "data": [] + }, + "headers": { + "Content-Type": "application/json", + "Connection": "keep-alive" + } + } +} diff --git a/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/orders_all_detailed.json b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/orders_all_detailed.json index 59d5635bcee..d058652ea7f 100644 --- a/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/orders_all_detailed.json +++ b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/orders/orders_all_detailed.json @@ -9,9 +9,6 @@ "path": { "equalTo": "/wc/v3/orders/&_method=get" }, - "query": { - "matches": "(.*)include(.*)" - }, "locale": { "matches": "(.*)" } diff --git a/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/payment_gateways.json b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/payment_gateways.json index 334329e1c97..f984cad5720 100644 --- a/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/payment_gateways.json +++ b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/payment_gateways.json @@ -8,7 +8,7 @@ }, "path": { "matches": "/wc/v3/payment_gateways(.*)" - }, + }, "locale": { "matches": "(.*)" } @@ -112,7 +112,7 @@ "title": "Cash on delivery", "description": "Pay with cash upon delivery.", "order": 2, - "enabled": false, + "enabled": true, "method_title": "Cash on delivery", "method_description": "Have your customers pay with cash (or by other means) upon delivery.", "method_supports": ["products"], diff --git a/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/system_status.json b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/system_status.json index 9a2f337146a..adb1ed50c88 100644 --- a/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/system_status.json +++ b/WooCommerce/src/androidTest/assets/mocks/mappings/jetpack-blogs/wc/system_status.json @@ -69,8 +69,8 @@ }, { "plugin": "woocommerce-gateway-stripe/woocommerce-gateway-stripe.php", "name": "WooCommerce Stripe Gateway", - "version": "6.1.0", - "version_latest": "6.1.0", + "version": "8.8.2", + "version_latest": "8.8.2", "url": "https://wordpress.org/plugins/woocommerce-gateway-stripe/", "author_name": "WooCommerce", "author_url": "https://woocommerce.com/", diff --git a/WooCommerce/src/androidTest/assets/mocks/mappings/woopos/stripe_account.json b/WooCommerce/src/androidTest/assets/mocks/mappings/woopos/stripe_account.json index ffaafe992ea..1cf400ed4ba 100644 --- a/WooCommerce/src/androidTest/assets/mocks/mappings/woopos/stripe_account.json +++ b/WooCommerce/src/androidTest/assets/mocks/mappings/woopos/stripe_account.json @@ -19,9 +19,10 @@ "jsonBody": { "data": { "country": "US", - "storeCurrencies": { + "store_currencies": { "default": "USD" - } + }, + "status": "enabled" } }, "headers": { diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/di/MockCardReaderManagerModule.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/di/MockCardReaderManagerModule.kt index fe0b1dca55b..ae9a6b199af 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/di/MockCardReaderManagerModule.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/di/MockCardReaderManagerModule.kt @@ -42,7 +42,7 @@ class MockCardReaderManagerModule { override val id: String get() = "ADEE123" override val type: String - get() = "reader" + get() = "COTS_DEVICE" override val currentBatteryLevel: Float get() = 1f override val firmwareVersion: String diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt index b522601cc3d..baf36ed416b 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/OrderListScreen.kt @@ -15,8 +15,7 @@ import org.hamcrest.Matchers class OrderListScreen : Screen(R.id.ordersList) { fun selectOrder(index: Int): SingleOrderScreen { - val correctedIndex = index + 1 // account for the header - selectItemAtIndexInRecyclerView(correctedIndex, R.id.ordersList, R.id.linearLayout) + selectItemAtIndexInRecyclerView(index, R.id.ordersList, R.id.linearLayout) return SingleOrderScreen() } diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/SingleOrderScreen.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/SingleOrderScreen.kt index 47b85059546..67f4fc349f2 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/SingleOrderScreen.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/screens/orders/SingleOrderScreen.kt @@ -14,7 +14,7 @@ import com.woocommerce.android.e2e.helpers.util.ProductData import com.woocommerce.android.e2e.helpers.util.Screen import org.hamcrest.Matchers -class SingleOrderScreen : Screen(R.id.toolbar) { +class SingleOrderScreen : Screen(R.id.orderStatus_subtitle) { fun goBackToOrdersScreen(): OrderListScreen { if (isElementDisplayed(R.id.orderDetail_container)) { pressBack() @@ -136,6 +136,7 @@ class SingleOrderScreen : Screen(R.id.toolbar) { } fun tapOnCollectPayment(): PaymentSelectionScreen { + scrollTo(R.id.paymentInfo_collectCardPresentPaymentButton) clickOn(R.id.paymentInfo_collectCardPresentPaymentButton) return PaymentSelectionScreen() } diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/tests/screenshot/ScreenshotTest.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/tests/screenshot/ScreenshotTest.kt index 8e9947318b0..90a94810f71 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/tests/screenshot/ScreenshotTest.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/e2e/tests/screenshot/ScreenshotTest.kt @@ -1,9 +1,11 @@ package com.woocommerce.android.e2e.tests.screenshot +import android.Manifest import android.util.Log import androidx.compose.ui.test.junit4.createComposeRule import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.GrantPermissionRule import com.woocommerce.android.AppPrefs import com.woocommerce.android.BuildConfig import com.woocommerce.android.e2e.helpers.InitializationRule @@ -45,6 +47,22 @@ class ScreenshotTest : TestBase(failOnUnmatchedWireMockRequests = false) { val localeTestRule = LocaleTestRule() @get:Rule(order = 4) + var locationPermissionRule: GrantPermissionRule? = GrantPermissionRule + .grant(Manifest.permission.ACCESS_FINE_LOCATION) + + @get:Rule(order = 5) + var bluetoothConnectPermissionRule: GrantPermissionRule? = GrantPermissionRule + .grant(Manifest.permission.BLUETOOTH_CONNECT) + + @get:Rule(order = 6) + var bluetoothScanPermissionRule: GrantPermissionRule? = GrantPermissionRule + .grant(Manifest.permission.BLUETOOTH_SCAN) + + @get:Rule(order = 7) + var notificationsPermissionRule: GrantPermissionRule? = GrantPermissionRule + .grant(Manifest.permission.POST_NOTIFICATIONS) + + @get:Rule(order = 8) var activityRule = ActivityScenarioRule(MainActivity::class.java) @Inject lateinit var wooNotificationBuilder: WooNotificationBuilder @@ -106,7 +124,7 @@ class ScreenshotTest : TestBase(failOnUnmatchedWireMockRequests = false) { AppPrefs.setShowCardReaderConnectedTutorial(false) // Skip card reader tutorial TabNavComponent() .gotoOrdersScreen() - .selectOrder(2) + .selectOrder(5) .tapOnCollectPayment() .chooseCardPayment() .thenTakeScreenshot("in-person-payments") diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt index beea17d0815..6b1f5bbc752 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt @@ -278,6 +278,7 @@ enum class AnalyticsEvent(override val siteless: Boolean = false) : IAnalyticsEv ORDER_DETAIL_EDIT_FLOW_FAILED, ORDER_DETAIL_EDIT_FLOW_CANCELED, ORDER_EDIT_BUTTON_TAPPED, + ORDER_EDIT_BUTTON_TAPPED_WHILE_DISABLED_FOR_CURRENCY_CONFLICT, PLUGINS_NOT_SYNCED_YET, // -- Order Creation @@ -1032,6 +1033,7 @@ enum class AnalyticsEvent(override val siteless: Boolean = false) : IAnalyticsEv BLAZE_CREATION_EDIT_DESTINATION_SAVE_TAPPED, BLAZE_CAMPAIGN_CREATION_FEEDBACK, BLAZE_CAMPAIGN_OBJECTIVE_SAVED, + BLAZE_SUGGESTIONS_LOADING_FAILED, // Hazmat Shipping Declaration CONTAINS_HAZMAT_CHECKED, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/FragmentExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/FragmentExt.kt index cd53be601b7..0c78c3455df 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/FragmentExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/FragmentExt.kt @@ -16,6 +16,9 @@ import com.woocommerce.android.support.help.HelpOrigin import com.woocommerce.android.ui.analytics.hub.AnalyticsHubFragment import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import java.time.Instant +import java.time.ZoneId +import java.time.ZonedDateTime import kotlin.math.abs /** @@ -198,19 +201,38 @@ fun Fragment.showDateRangePicker( toMillis: Long = System.currentTimeMillis(), onCustomRangeSelected: (Long, Long) -> Unit ) { - val datePicker = - MaterialDatePicker.Builder.dateRangePicker() - .setTitleText(getString(R.string.orderfilters_date_range_picker_title)) - .setSelection(androidx.core.util.Pair(fromMillis, toMillis)) - .setCalendarConstraints( - CalendarConstraints.Builder() - .setEnd(MaterialDatePicker.todayInUtcMilliseconds()) - .setValidator(DateValidatorPointBackward.now()) - .build() + fun shiftTime(time: Long, originalZoneId: ZoneId, targetZoneId: ZoneId): Long { + // The timestamps returned by the MaterialDatePicker are in UTC timezone, if we use them directly + // we will get a shift in the selected range. + // To avoid this, we get the local date using UTC timestamps and then convert it to the selected timezone + // See: https://github.com/material-components/material-components-android/issues/882 + val originalDateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(time), originalZoneId).toLocalDateTime() + val targetDateTime = ZonedDateTime.of(originalDateTime, targetZoneId) + return targetDateTime.toInstant().toEpochMilli() + } + + val deviceZoneId = ZoneId.systemDefault() + val datePicker = MaterialDatePicker.Builder.dateRangePicker() + .setTitleText(getString(R.string.orderfilters_date_range_picker_title)) + .setSelection( + androidx.core.util.Pair( + shiftTime(fromMillis, deviceZoneId, ZoneId.of("UTC")), + shiftTime(toMillis, deviceZoneId, ZoneId.of("UTC")) ) - .build() + ) + .setCalendarConstraints( + CalendarConstraints.Builder() + .setEnd(MaterialDatePicker.todayInUtcMilliseconds()) + .setValidator(DateValidatorPointBackward.now()) + .build() + ) + .build() + datePicker.show(parentFragmentManager, AnalyticsHubFragment.DATE_PICKER_FRAGMENT_TAG) datePicker.addOnPositiveButtonClickListener { - onCustomRangeSelected(it?.first ?: 0L, it.second ?: 0L) + val start = shiftTime(it.first ?: 0, ZoneId.of("UTC"), deviceZoneId) + val end = shiftTime(it.second ?: 0, ZoneId.of("UTC"), deviceZoneId) + + onCustomRangeSelected(start, end) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt index ea5ddd86748..fbb172aa71d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeRepository.kt @@ -149,7 +149,7 @@ class BlazeRepository @Inject constructor( suspend fun fetchAdSuggestions(productId: Long): Result> { fun List.mapToUiModel(): List { - return map { AiSuggestionForAd(it.tagLine, it.description) } + return map { AiSuggestionForAd(it.tagLine, it.description, it.ctaText) } } val result = blazeCampaignsStore.fetchBlazeAdSuggestions(selectedSite.get(), productId) @@ -157,7 +157,7 @@ class BlazeRepository @Inject constructor( return when { result.isError -> { WooLog.w(WooLog.T.BLAZE, "Failed to fetch ad suggestions: ${result.error}") - Result.failure(OnChangedException(result.error)) + Result.failure(OnChangedException(result.error, result.error.message)) } else -> Result.success(result.model?.mapToUiModel() ?: emptyList()) @@ -194,7 +194,8 @@ class BlazeRepository @Inject constructor( targetUrl = product.permalink, parameters = emptyMap() ), - objectiveId = appPrefsWrapper.blazeCampaignSelectedObjective + objectiveId = appPrefsWrapper.blazeCampaignSelectedObjective, + ctaText = "" ) } @@ -273,6 +274,7 @@ class BlazeRepository @Inject constructor( ) } + @Suppress("LongMethod") suspend fun createCampaign( campaignDetails: CampaignDetails, paymentMethodId: String @@ -297,6 +299,7 @@ class BlazeRepository @Inject constructor( targetResourceId = campaignDetails.productId, tagLine = campaignDetails.tagLine, description = campaignDetails.description, + ctaText = campaignDetails.ctaText, startDate = campaignDetails.budget.startDate, endDate = campaignDetails.budget.endDate, budget = BlazeCampaignCreationRequestBudget( @@ -394,6 +397,7 @@ class BlazeRepository @Inject constructor( val productId: Long, val tagLine: String, val description: String, + val ctaText: String, val campaignImage: BlazeCampaignImage, val budget: Budget, val targetingParameters: TargetingParameters, @@ -446,6 +450,7 @@ class BlazeRepository @Inject constructor( data class AiSuggestionForAd( val tagLine: String, val description: String, + val ctaText: String ) : Parcelable @Parcelize diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdScreen.kt index f880be2d77a..cd396ece16a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdScreen.kt @@ -71,7 +71,8 @@ fun BlazeCampaignCreationPreviewScreen(viewModel: BlazeCampaignCreationEditAdVie onMediaPickerDialogDismissed = viewModel::onMediaPickerDialogDismissed, onProductImagesRequested = viewModel::onProductImagesRequested, onMediaLibraryRequested = viewModel::onMediaLibraryRequested, - onSaveTapped = viewModel::onSaveTapped + onSaveTapped = viewModel::onSaveTapped, + onCtaTextChanged = viewModel::onCtaTextChanged ) } } @@ -88,7 +89,8 @@ private fun BlazeCampaignCreationEditAdScreen( onMediaPickerDialogDismissed: () -> Unit, onProductImagesRequested: () -> Unit, onMediaLibraryRequested: (DataSource) -> Unit, - onSaveTapped: () -> Unit + onSaveTapped: () -> Unit, + onCtaTextChanged: (String) -> Unit ) { if (viewState.isMediaPickerDialogVisible) { MediaPickerDialog( @@ -123,7 +125,8 @@ private fun BlazeCampaignCreationEditAdScreen( onDescriptionChanged, onChangeImageTapped, onPreviousSuggestionTapped, - onNextSuggestionTapped + onNextSuggestionTapped, + onCtaTextChanged ) } } @@ -137,6 +140,7 @@ fun CampaignEditAdContent( onChangeImageTapped: () -> Unit, onPreviousSuggestionTapped: () -> Unit, onNextSuggestionTapped: () -> Unit, + onCtaTextChanged: (String) -> Unit ) { Column( modifier = Modifier @@ -156,7 +160,8 @@ fun CampaignEditAdContent( onTagLineChanged = onTagLineChanged, onDescriptionChanged = onDescriptionChanged, onPreviousSuggestionTapped = onPreviousSuggestionTapped, - onNextSuggestionTapped = onNextSuggestionTapped + onNextSuggestionTapped = onNextSuggestionTapped, + onCtaTextChanged = onCtaTextChanged ) } } @@ -167,7 +172,8 @@ private fun AdDataSection( onTagLineChanged: (String) -> Unit, onDescriptionChanged: (String) -> Unit, onPreviousSuggestionTapped: () -> Unit, - onNextSuggestionTapped: () -> Unit + onNextSuggestionTapped: () -> Unit, + onCtaTextChanged: (String) -> Unit ) { Column( modifier = Modifier @@ -175,62 +181,16 @@ private fun AdDataSection( .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { - Box { - WCOutlinedTextField( - value = viewState.tagLine, - onValueChange = onTagLineChanged, - label = stringResource(id = string.blaze_campaign_edit_ad_change_tagline_title), - singleLine = true, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) - ) - - CornerCharacterWarning( - charsLeft = viewState.taglineCharactersRemaining, - modifier = Modifier.align(Alignment.TopEnd) - ) - } - - Text( - text = stringResource( - id = string.blaze_campaign_edit_ad_characters_remaining, - viewState.taglineCharactersRemaining - ), - style = MaterialTheme.typography.caption, - color = colorResource(id = color.color_on_surface_disabled), - modifier = Modifier - .padding(top = dimensionResource(id = dimen.minor_100)) - .fillMaxWidth() + TaglineInputText(viewState, onTagLineChanged) + DescriptionInputText( + viewState, + onDescriptionChanged, + modifier = Modifier.padding(top = dimensionResource(id = dimen.major_150)) ) - - Box( - modifier = Modifier - .padding(top = dimensionResource(id = dimen.major_150)) - ) { - WCOutlinedTextField( - value = viewState.description, - onValueChange = onDescriptionChanged, - label = stringResource(id = string.blaze_campaign_edit_ad_change_description_title), - maxLines = 3, - minLines = 3, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next) - ) - - CornerCharacterWarning( - charsLeft = viewState.descriptionCharactersRemaining, - modifier = Modifier.align(Alignment.TopEnd) - ) - } - - Text( - text = stringResource( - id = string.blaze_campaign_edit_ad_characters_remaining, - viewState.descriptionCharactersRemaining - ), - style = MaterialTheme.typography.caption, - color = colorResource(id = color.color_on_surface_disabled), - modifier = Modifier - .padding(top = dimensionResource(id = dimen.minor_100)) - .fillMaxWidth() + CallToActionInputText( + viewState, + onCtaTextChanged, + modifier = Modifier.padding(top = dimensionResource(id = dimen.major_150)) ) if (viewState.suggestions.size > 1) { @@ -271,6 +231,97 @@ private fun AdDataSection( } } +@Composable +private fun DescriptionInputText( + viewState: ViewState, + onDescriptionChanged: (String) -> Unit, + modifier: Modifier = Modifier +) { + val isError = viewState.description.isEmpty() + Box(modifier = modifier) { + WCOutlinedTextField( + value = viewState.description, + onValueChange = onDescriptionChanged, + label = stringResource(id = string.blaze_campaign_edit_ad_change_description_title), + maxLines = 3, + minLines = 3, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), + helperText = when { + isError -> stringResource(id = string.blaze_campaign_edit_ad_change_description_empty_error) + else -> + stringResource( + id = string.blaze_campaign_edit_ad_characters_remaining, + viewState.descriptionCharactersRemaining + ) + }, + isError = isError + ) + + CornerCharacterWarning( + charsLeft = viewState.descriptionCharactersRemaining, + modifier = Modifier.align(Alignment.TopEnd) + ) + } +} + +@Composable +private fun TaglineInputText( + viewState: ViewState, + onTagLineChanged: (String) -> Unit, + modifier: Modifier = Modifier +) { + val isError = viewState.tagLine.isEmpty() + Box(modifier = modifier) { + WCOutlinedTextField( + value = viewState.tagLine, + onValueChange = onTagLineChanged, + label = stringResource(id = string.blaze_campaign_edit_ad_change_tagline_title), + singleLine = true, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), + helperText = when { + isError -> stringResource(id = string.blaze_campaign_edit_ad_change_tagline_empty_error) + else -> + stringResource( + id = string.blaze_campaign_edit_ad_characters_remaining, + viewState.taglineCharactersRemaining + ) + }, + isError = isError + ) + + CornerCharacterWarning( + charsLeft = viewState.taglineCharactersRemaining, + modifier = Modifier.align(Alignment.TopEnd) + ) + } +} + +@Composable +private fun CallToActionInputText( + viewState: ViewState, + onCtaTextChanged: (String) -> Unit, + modifier: Modifier = Modifier +) { + Box(modifier = modifier) { + WCOutlinedTextField( + value = viewState.ctaText, + onValueChange = onCtaTextChanged, + label = stringResource(id = string.blaze_campaign_edit_ad_change_cta_text_title), + singleLine = true, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), + helperText = stringResource( + id = string.blaze_campaign_edit_ad_characters_remaining, + viewState.ctaTextCharactersRemaining + ), + ) + + CornerCharacterWarning( + charsLeft = viewState.ctaTextCharactersRemaining, + modifier = Modifier.align(Alignment.TopEnd) + ) + } +} + @Composable private fun CornerCharacterWarning(charsLeft: Int, modifier: Modifier = Modifier) { if (charsLeft < 10) { @@ -380,7 +431,8 @@ fun PreviewCampaignEditAdContent() { onDescriptionChanged = { }, onChangeImageTapped = { }, onPreviousSuggestionTapped = { }, - onNextSuggestionTapped = { } + onNextSuggestionTapped = { }, + onCtaTextChanged = { }, ) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt index ca7fcfe6396..46b05d7d3a8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/ad/BlazeCampaignCreationEditAdViewModel.kt @@ -33,6 +33,7 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( companion object { private const val TAGLINE_MAX_LENGTH = 32 private const val DESCRIPTION_MAX_LENGTH = 140 + private const val CTA_TEST_MAX_LENGTH = 26 } private val navArgs: BlazeCampaignCreationEditAdFragmentArgs by savedStateHandle.navArgs() @@ -49,7 +50,7 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( private fun loadSuggestions() { viewModelScope.launch { - val passedDetails = AiSuggestionForAd(navArgs.tagline, navArgs.description) + val passedDetails = AiSuggestionForAd(navArgs.tagline, navArgs.description, navArgs.ctaText) val suggestions = navArgs.aiSuggestionsForAd.toList() _viewState.update { it.copy( @@ -83,7 +84,8 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( EditAdResult( tagline = _viewState.value.tagLine, description = _viewState.value.description, - campaignImage = _viewState.value.adImage + campaignImage = _viewState.value.adImage, + ctaText = _viewState.value.ctaText ) ) ) @@ -107,11 +109,23 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( } fun onTagLineChanged(tagLine: String) { - updateSuggestion(AiSuggestionForAd(tagLine.take(TAGLINE_MAX_LENGTH), _viewState.value.description)) + updateSuggestion( + AiSuggestionForAd( + tagLine.take(TAGLINE_MAX_LENGTH), + _viewState.value.description, + _viewState.value.ctaText + ) + ) } fun onDescriptionChanged(description: String) { - updateSuggestion(AiSuggestionForAd(_viewState.value.tagLine, description.take(DESCRIPTION_MAX_LENGTH))) + updateSuggestion( + AiSuggestionForAd( + _viewState.value.tagLine, + description.take(DESCRIPTION_MAX_LENGTH), + _viewState.value.ctaText + ) + ) } fun onLocalImageSelected(uri: String) { @@ -175,6 +189,16 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( setMediaPickerDialogVisibility(false) } + fun onCtaTextChanged(ctaText: String) { + updateSuggestion( + AiSuggestionForAd( + _viewState.value.tagLine, + _viewState.value.description, + ctaText.take(CTA_TEST_MAX_LENGTH) + ) + ) + } + data class ShowMediaLibrary(val source: MediaPickerSetup.DataSource) : Event() data class ShowProductImagePicker(val productId: Long) : Event() @@ -189,10 +213,14 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( get() = suggestions.getOrNull(suggestionIndex)?.tagLine ?: "" val description: String get() = suggestions.getOrNull(suggestionIndex)?.description ?: "" + val ctaText: String + get() = suggestions.getOrNull(suggestionIndex)?.ctaText ?: "" val taglineCharactersRemaining: Int get() = TAGLINE_MAX_LENGTH - (suggestions.getOrNull(suggestionIndex)?.tagLine?.length ?: 0) val descriptionCharactersRemaining: Int get() = DESCRIPTION_MAX_LENGTH - (suggestions.getOrNull(suggestionIndex)?.description?.length ?: 0) + val ctaTextCharactersRemaining: Int + get() = CTA_TEST_MAX_LENGTH - (suggestions.getOrNull(suggestionIndex)?.ctaText?.length ?: 0) val isPreviousSuggestionButtonEnabled: Boolean get() = suggestionIndex > 0 val isNextSuggestionButtonEnabled: Boolean @@ -203,6 +231,7 @@ class BlazeCampaignCreationEditAdViewModel @Inject constructor( data class EditAdResult( val tagline: String, val description: String, - val campaignImage: BlazeRepository.BlazeCampaignImage + val campaignImage: BlazeRepository.BlazeCampaignImage, + val ctaText: String ) : Parcelable } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt index 29b55aad071..e806d405725 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewFragment.kt @@ -75,6 +75,7 @@ class BlazeCampaignCreationPreviewFragment : BaseFragment() { productId = event.productId, tagline = event.tagLine, description = event.description, + ctaText = event.ctaText, adImage = event.campaignImage, aiSuggestionsForAd = event.aiSuggestions.toTypedArray() ) @@ -120,7 +121,7 @@ class BlazeCampaignCreationPreviewFragment : BaseFragment() { private fun handleResults() { handleResult(BlazeCampaignCreationEditAdFragment.EDIT_AD_RESULT) { - viewModel.onAdUpdated(it.tagline, it.description, it.campaignImage) + viewModel.onAdUpdated(it) } handleResult(BlazeCampaignObjectiveFragment.BLAZE_OBJECTIVE_SELECTION_RESULT) { viewModel.onObjectiveUpdated(it.objectiveId) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt index 217ae3f7218..38a9bcf7f72 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -27,6 +28,7 @@ import androidx.compose.material.Scaffold import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.ArrowForwardIos import androidx.compose.runtime.Composable import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment @@ -193,7 +195,7 @@ fun AdDetailsHeader( onEditAdClicked: () -> Unit, modifier: Modifier = Modifier, ) { - CampaignHeader( + AdPreview( adDetails = adDetails, onEditAdClicked = onEditAdClicked, modifier = modifier @@ -205,7 +207,7 @@ fun AdDetailsHeader( } @Composable -fun CampaignHeader( +fun AdPreview( adDetails: AdDetails, onEditAdClicked: () -> Unit, modifier: Modifier = Modifier @@ -263,13 +265,21 @@ fun CampaignHeader( style = MaterialTheme.typography.subtitle1, fontWeight = FontWeight.Bold, ) + if (adDetails.ctaText.isEmpty()) { + DefaultBlazeButton( + modifier = Modifier + .padding(start = 16.dp) + .align(Alignment.Top) + ) + } + } + if (adDetails.ctaText.isNotEmpty()) { WCColoredButton( - text = stringResource(id = R.string.blaze_campaign_preview_shop_now_button), - modifier = Modifier - .padding(start = 16.dp), + modifier = Modifier.padding(top = 8.dp), + text = adDetails.ctaText, colors = ButtonDefaults.buttonColors( - contentColor = colorResource(id = R.color.color_on_secondary), - backgroundColor = colorResource(id = R.color.blaze_campaign_preview_shop_now_button), + contentColor = colorResource(id = R.color.color_on_primary_surface), + backgroundColor = colorResource(id = R.color.blaze_ad_cta_background), ), onClick = { /*TODO*/ }, ) @@ -365,6 +375,26 @@ private fun CampaignPropertyGroupItem( } } +@Composable +private fun DefaultBlazeButton(modifier: Modifier = Modifier) { + Box( + modifier = modifier + .size(40.dp) + .clip(RoundedCornerShape(20.dp)) + .background(color = colorResource(id = R.color.blaze_ad_cta_background)) + ) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowForwardIos, + contentDescription = null, + tint = colorResource(id = R.color.color_on_primary_surface), + modifier = Modifier + .align(Alignment.Center) + .size(32.dp) + .padding(6.dp) + ) + } +} + @Composable private fun CampaignPropertyItem( item: CampaignDetailItemUi, @@ -418,6 +448,7 @@ fun CampaignScreenPreview() { productId = 123, description = "Get the latest white t-shirts", tagLine = "From 45.00 USD", + ctaText = "Shop Now", campaignImageUrl = "https://rb.gy/gmjuwb", isContentSuggestedByAi = true ), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt index 70530bcceb0..e2fc24307b6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import com.woocommerce.android.R +import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsEvent.BLAZE_CREATION_CONFIRM_DETAILS_TAPPED import com.woocommerce.android.analytics.AnalyticsEvent.BLAZE_CREATION_EDIT_AD_TAPPED import com.woocommerce.android.analytics.AnalyticsEvent.BLAZE_CREATION_FORM_DISPLAYED @@ -18,6 +19,7 @@ import com.woocommerce.android.ui.blaze.BlazeRepository.AiSuggestionForAd import com.woocommerce.android.ui.blaze.BlazeRepository.CampaignDetails import com.woocommerce.android.ui.blaze.BlazeRepository.Objective import com.woocommerce.android.ui.blaze.Location +import com.woocommerce.android.ui.blaze.creation.ad.BlazeCampaignCreationEditAdViewModel.EditAdResult import com.woocommerce.android.ui.blaze.creation.targets.BlazeTargetType import com.woocommerce.android.ui.blaze.creation.targets.BlazeTargetType.DEVICE import com.woocommerce.android.ui.blaze.creation.targets.BlazeTargetType.INTEREST @@ -75,6 +77,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( productId = navArgs.productId, description = campaignDetails.description, tagLine = campaignDetails.tagLine, + ctaText = campaignDetails.ctaText, campaignImageUrl = campaignDetails.campaignImage.uri, isContentSuggestedByAi = isAdContentGeneratedByAi(campaignDetails) ) @@ -108,6 +111,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( productId = navArgs.productId, tagLine = it.tagLine, description = it.description, + ctaText = it.ctaText, campaignImage = it.campaignImage, aiSuggestions = aiSuggestions ) @@ -115,12 +119,13 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( } } - fun onAdUpdated(tagline: String, description: String, campaignImage: BlazeRepository.BlazeCampaignImage) { + fun onAdUpdated(updatedAd: EditAdResult) { campaignDetails.update { it?.copy( - tagLine = tagline, - description = description, - campaignImage = campaignImage + tagLine = updatedAd.tagline, + description = updatedAd.description, + campaignImage = updatedAd.campaignImage, + ctaText = updatedAd.ctaText ) } } @@ -241,7 +246,8 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( private fun isAdContentGeneratedByAi(campaignDetails: CampaignDetails?): Boolean = aiSuggestions.any { it.tagLine == campaignDetails?.tagLine && - it.description == campaignDetails.description + it.description == campaignDetails.description && + it.ctaText == campaignDetails.ctaText } private fun loadData() { @@ -254,16 +260,29 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( blazeRepository.fetchDevices() blazeRepository.fetchInterests() - blazeRepository.fetchAdSuggestions(productId = navArgs.productId).getOrNull().let { suggestions -> - aiSuggestions = suggestions.orEmpty() - adDetailsState.value = AdDetailsUiState.LOADED - campaignDetails.update { - it?.copy( - tagLine = suggestions?.firstOrNull()?.tagLine.orEmpty(), - description = suggestions?.firstOrNull()?.description.orEmpty(), - ) + blazeRepository.fetchAdSuggestions(productId = navArgs.productId) + .fold( + onSuccess = { suggestions -> + aiSuggestions = suggestions + campaignDetails.update { + it?.copy( + tagLine = suggestions.firstOrNull()?.tagLine.orEmpty(), + description = suggestions.firstOrNull()?.description.orEmpty(), + ctaText = suggestions.firstOrNull()?.ctaText.orEmpty() + ) + } + }, + onFailure = { error -> + analyticsTrackerWrapper.track( + stat = AnalyticsEvent.BLAZE_SUGGESTIONS_LOADING_FAILED, + properties = mapOf( + AnalyticsTracker.KEY_ERROR to error.message + ) + ) + } + ).also { + adDetailsState.value = AdDetailsUiState.LOADED } - } blazeRepository.fetchObjectives() } } @@ -400,6 +419,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( val productId: Long, val description: String, val tagLine: String, + val ctaText: String, val campaignImageUrl: String?, val isContentSuggestedByAi: Boolean, ) : AdDetailsUi @@ -442,6 +462,7 @@ class BlazeCampaignCreationPreviewViewModel @Inject constructor( val productId: Long, val tagLine: String, val description: String, + val ctaText: String, val campaignImage: BlazeRepository.BlazeCampaignImage, val aiSuggestions: List ) : MultiLiveEvent.Event() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/compose/component/web/WebView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/compose/component/web/WCWebView.kt similarity index 98% rename from WooCommerce/src/main/kotlin/com/woocommerce/android/ui/compose/component/web/WebView.kt rename to WooCommerce/src/main/kotlin/com/woocommerce/android/ui/compose/component/web/WCWebView.kt index 5a440cc8ff9..753817677d2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/compose/component/web/WebView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/compose/component/web/WCWebView.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -61,7 +62,7 @@ fun WCWebView( progressIndicator: WebViewProgressIndicator = Linear() ) { var webView by remember { mutableStateOf(null) } - var progress by remember { mutableStateOf(0) } + var progress by remember { mutableIntStateOf(0) } var lastLoadedUrl by remember { mutableStateOf("") } var canGoBack by remember { mutableStateOf(false) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginWhatIsJetpackDialogFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginWhatIsJetpackDialogFragment.kt index 34919503985..4a04d3fedea 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginWhatIsJetpackDialogFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginWhatIsJetpackDialogFragment.kt @@ -18,6 +18,7 @@ class LoginWhatIsJetpackDialogFragment : DialogFragment() { const val TAG = "LoginWhatIsJetpackDialogFragment" } + @Deprecated("Deprecated in Java") @Suppress("DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt index 02d388da570..8b5f17d864e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt @@ -435,6 +435,7 @@ class MainActivity : } } + @Deprecated("Deprecated in Java") override fun onBackPressed() { AnalyticsTracker.trackBackPressed(this) @@ -1231,6 +1232,7 @@ class MainActivity : ) } + @Deprecated("Deprecated in Java") override fun onAttachFragment(fragment: Fragment) { super.onAttachFragment(fragment) updateAppBarVisibility(fragment) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/IsStoreCurrencyMatch.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/IsStoreCurrencyMatch.kt new file mode 100644 index 00000000000..e4ab2a93dfc --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/IsStoreCurrencyMatch.kt @@ -0,0 +1,28 @@ +package com.woocommerce.android.ui.orders + +import com.woocommerce.android.tools.SelectedSite +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.wordpress.android.fluxc.store.WooCommerceStore +import javax.inject.Inject + +class IsStoreCurrencyMatch @Inject constructor( + private val wooCommerceStore: WooCommerceStore, + private val selectedSite: SelectedSite +) { + + suspend operator fun invoke(orderCurrency: String): CurrencyMatchResult { + val storeCurrency = withContext(Dispatchers.IO) { + wooCommerceStore.getSiteSettings(selectedSite.get())?.currencyCode + } + return CurrencyMatchResult( + isMatch = storeCurrency.equals(orderCurrency, ignoreCase = true), + storeCurrency = storeCurrency + ) + } +} + +data class CurrencyMatchResult( + val isMatch: Boolean, + val storeCurrency: String? +) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditFormFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditFormFragment.kt index 4235c448ee5..dd73b61bdb1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditFormFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditFormFragment.kt @@ -423,10 +423,11 @@ class OrderCreateEditFormFragment : binding.shippingLines.apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { - viewModel.shippingLineList.observeAsState().value?.let { shippingLines -> + viewModel.shippingLineSection.observeAsState().value?.let { shippingLineSection -> WooThemeWithBackground { ShippingLineFormSection( - shippingLineDetails = shippingLines, + shippingLineDetails = shippingLineSection.shippingLines, + isEnabled = shippingLineSection.isEnabled, formatCurrency = { amount -> currencyFormatter.formatCurrency(amount) }, modifier = Modifier.padding(bottom = 1.dp), onAddClicked = { viewModel.onAddOrEditShippingClicked() }, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt index dad9ed6d48e..35bd1026ebf 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreateEditViewModel.kt @@ -7,9 +7,9 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.asFlow import androidx.lifecycle.asLiveData import androidx.lifecycle.distinctUntilChanged +import androidx.lifecycle.map import androidx.lifecycle.viewModelScope import com.woocommerce.android.AppPrefs import com.woocommerce.android.R.string @@ -116,10 +116,10 @@ import com.woocommerce.android.ui.orders.creation.navigation.OrderCreateEditNavi import com.woocommerce.android.ui.orders.creation.navigation.OrderCreateEditNavigationTarget.TaxRateSelector import com.woocommerce.android.ui.orders.creation.product.discount.CurrencySymbolFinder import com.woocommerce.android.ui.orders.creation.shipping.GetShippingMethodsWithOtherValue -import com.woocommerce.android.ui.orders.creation.shipping.ShippingLineDetails -import com.woocommerce.android.ui.orders.creation.shipping.ShippingMethodsRepository +import com.woocommerce.android.ui.orders.creation.shipping.ShippingLineSection import com.woocommerce.android.ui.orders.creation.shipping.ShippingUpdateResult import com.woocommerce.android.ui.orders.creation.shipping.getMethodIdOrDefault +import com.woocommerce.android.ui.orders.creation.shipping.toShippingLineDetails import com.woocommerce.android.ui.orders.creation.taxes.GetAddressFromTaxRate import com.woocommerce.android.ui.orders.creation.taxes.GetTaxRatesInfoDialogViewState import com.woocommerce.android.ui.orders.creation.taxes.TaxBasedOnSetting @@ -171,10 +171,8 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.take import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.updateAndGet -import kotlinx.coroutines.flow.withIndex import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.parcelize.IgnoredOnParcel @@ -380,30 +378,19 @@ class OrderCreateEditViewModel @Inject constructor( private val giftCardWasEnabledAtLeastOnce: MutableStateFlow = savedState.getStateFlow(viewModelScope, false) - val shippingLineList = - combine( - _orderDraft.filter { it.shippingLines.isNotEmpty() } - .map { it.shippingLines.filter { line -> line.methodId != null } }, - getShippingMethodsWithOtherValue().withIndex() - ) { shippingLines, shippingMethods -> - val shippingMethodsMap = shippingMethods.value.associateBy { it.id } - - shippingLines.map { shippingLine -> - val method = shippingLine.methodId?.let { - if (it == " ") { - shippingMethodsMap[ShippingMethodsRepository.NA_ID] - } else { - shippingMethodsMap[it] - } - } - ShippingLineDetails( - id = shippingLine.itemId, - name = shippingLine.methodTitle, - shippingMethod = method, - amount = shippingLine.total + val shippingLineSection = viewStateData.liveData + .combineWith( + orderDraft.map { it.shippingLines }, + getShippingMethodsWithOtherValue().asLiveData() + ) { viewState, shippingLines, shippingMethods -> + if (viewState == null || shippingLines == null || shippingMethods == null) return@combineWith null + shippingLines.toShippingLineDetails(shippingMethods)?.let { shippingLineDetails -> + ShippingLineSection( + shippingLines = shippingLineDetails, + isEnabled = viewState.isIdle && viewState.isEditable ) } - }.asLiveData() + }.distinctUntilChanged() private val _couponLinesLiveData = MediatorLiveData(CouponSection(emptyList(), true)) val couponLinesLiveData = _couponLinesLiveData.distinctUntilChanged() @@ -480,20 +467,20 @@ class OrderCreateEditViewModel @Inject constructor( } } + private var _isFirstShippingLineChange = true + private fun shouldDisplayShippingFeedback() { launch { - shippingLineList - .asFlow() - .drop(1) - .take(1) - .takeIf { shouldDisplayShippingLinesFeedback() } - ?.collect { + if (_isFirstShippingLineChange && shouldDisplayShippingLinesFeedback()) { + launch { delay(DELAY_BEFORE_SHOWING_SHIPPING_FEEDBACK) viewState = viewState.copy( showShippingFeedback = true, isTotalsExpanded = false ) + _isFirstShippingLineChange = false } + } } } @@ -1622,6 +1609,7 @@ class OrderCreateEditViewModel @Inject constructor( draft.copy(shippingLines = shipping) } + shouldDisplayShippingFeedback() } fun onRemoveShipping(itemId: Long) { @@ -1644,6 +1632,7 @@ class OrderCreateEditViewModel @Inject constructor( } ) } + shouldDisplayShippingFeedback() } fun onFeeEdited(feeValue: BigDecimal) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineDetails.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineDetails.kt index 683195a7f7a..abceba8fa5f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineDetails.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineDetails.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.orders.creation.shipping +import com.woocommerce.android.model.Order import com.woocommerce.android.model.ShippingMethod import java.math.BigDecimal @@ -9,3 +10,29 @@ data class ShippingLineDetails( val amount: BigDecimal, val name: String ) + +fun List.toShippingLineDetails( + shippingMethods: List, +): List? { + if (this.isEmpty()) { + return null + } + val filteredShippingLines = this.filter { line -> line.methodId != null } + val shippingMethodsMap = shippingMethods.associateBy { it.id } + return filteredShippingLines.map { shippingLine -> + val method = shippingLine.methodId?.let { + if (it == " ") { + shippingMethodsMap[ShippingMethodsRepository.NA_ID] + } else { + shippingMethodsMap[it] + } + } + + ShippingLineDetails( + id = shippingLine.itemId, + name = shippingLine.methodTitle, + shippingMethod = method, + amount = shippingLine.total + ) + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineFormSection.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineFormSection.kt index 3c346233a51..5b84bdffa37 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineFormSection.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineFormSection.kt @@ -1,6 +1,5 @@ package com.woocommerce.android.ui.orders.creation.shipping -import android.content.res.Configuration import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.border import androidx.compose.foundation.clickable @@ -10,6 +9,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card import androidx.compose.material.Icon @@ -22,11 +22,13 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight @@ -35,13 +37,13 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.woocommerce.android.R -import com.woocommerce.android.model.ShippingMethod import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground import java.math.BigDecimal @Composable fun ShippingLineFormSection( shippingLineDetails: List, + isEnabled: Boolean, onAddClicked: () -> Unit, onEditClicked: (id: Long) -> Unit, formatCurrency: (amount: BigDecimal) -> String, @@ -58,23 +60,37 @@ fun ShippingLineFormSection( .weight(2f, true) .align(Alignment.CenterVertically) ) - Icon( - imageVector = Icons.Default.Add, - contentDescription = stringResource(id = R.string.order_creation_add_shipping), - modifier = Modifier - .align(Alignment.CenterVertically) - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = null - ) { onAddClicked() }, - tint = MaterialTheme.colors.primary - ) + if (isEnabled) { + Icon( + imageVector = Icons.Default.Add, + contentDescription = stringResource(id = R.string.order_creation_add_shipping), + modifier = Modifier + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null + ) { + onAddClicked() + } + .align(Alignment.CenterVertically), + tint = MaterialTheme.colors.primary + ) + } else { + Icon( + painter = painterResource(id = R.drawable.ic_lock), + contentDescription = null, + modifier = Modifier + .align(Alignment.CenterVertically) + .size(dimensionResource(id = R.dimen.image_minor_40)), + tint = MaterialTheme.colors.primary + ) + } } shippingLineDetails.forEachIndexed { i, shippingDetails -> val itemModifier = if (i == 0) Modifier else Modifier.padding(top = 8.dp) ShippingLineEditCard( shippingLine = shippingDetails, + isEnabled = isEnabled, onEdit = onEditClicked, formatCurrency = formatCurrency, modifier = itemModifier @@ -88,20 +104,28 @@ fun ShippingLineFormSection( @Composable fun ShippingLineEditCard( shippingLine: ShippingLineDetails, + isEnabled: Boolean, formatCurrency: (amount: BigDecimal) -> String, onEdit: (id: Long) -> Unit, modifier: Modifier = Modifier ) { + val rowModifier = if (isEnabled) { + modifier + .clip(RoundedCornerShape(dimensionResource(id = R.dimen.corner_radius_large))) + .clickable { onEdit(shippingLine.id) } + } else { + modifier + } + Row( verticalAlignment = Alignment.CenterVertically, - modifier = modifier + modifier = rowModifier .fillMaxWidth() .border( brush = SolidColor(MaterialTheme.colors.onSurface.copy(alpha = 0.12f)), width = 1.dp, shape = RoundedCornerShape(dimensionResource(id = R.dimen.corner_radius_large)) ) - .clickable { onEdit(shippingLine.id) } .padding(dimensionResource(id = R.dimen.major_100)) ) { @@ -143,26 +167,36 @@ fun ShippingLineEditCard( color = colorResource(id = R.color.color_on_surface), modifier = Modifier.align(Alignment.CenterVertically) ) - Icon( - imageVector = Icons.Outlined.Edit, - contentDescription = null, - modifier = Modifier - .align(Alignment.CenterVertically) - .padding(start = 16.dp) - ) + if (isEnabled) { + Icon( + imageVector = Icons.Outlined.Edit, + contentDescription = null, + modifier = Modifier + .align(Alignment.CenterVertically) + .padding(start = 16.dp) + ) + } } } @Preview -@Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable -fun ShippingLineDetailsPreview() { - WooThemeWithBackground { +fun ShippingLineFormSectionLockedPreview() { + val shippingDetails = List(3) { i -> ShippingLineDetails( - id = 1L, - name = "UPS Shipping", - shippingMethod = ShippingMethod(id = "ups", title = "UPS"), - amount = BigDecimal.TEN, + id = i * 1L, + shippingMethod = null, + amount = BigDecimal.TEN * i.toBigDecimal(), + name = "Shipping $i" + ) + } + WooThemeWithBackground { + ShippingLineFormSection( + shippingLineDetails = shippingDetails, + formatCurrency = { it.toString() }, + isEnabled = false, + onAddClicked = { }, + onEditClicked = { } ) } } @@ -182,6 +216,7 @@ fun ShippingLineFormSectionPreview() { ShippingLineFormSection( shippingLineDetails = shippingDetails, formatCurrency = { it.toString() }, + isEnabled = true, onAddClicked = { }, onEditClicked = { } ) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineSection.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineSection.kt new file mode 100644 index 00000000000..47822631f8f --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/shipping/ShippingLineSection.kt @@ -0,0 +1,6 @@ +package com.woocommerce.android.ui.orders.creation.shipping + +data class ShippingLineSection( + val shippingLines: List, + val isEnabled: Boolean +) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailTracker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailTracker.kt index 195b3b88586..55a420df075 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailTracker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailTracker.kt @@ -26,6 +26,10 @@ class OrderDetailTracker @Inject constructor( ) } + fun trackOrderAndStoreCurrencyMismatchWhenEditButtonTapped() { + trackerWrapper.track(AnalyticsEvent.ORDER_EDIT_BUTTON_TAPPED_WHILE_DISABLED_FOR_CURRENCY_CONFLICT) + } + suspend fun trackReceiptViewTapped(orderId: Long, orderStatus: Order.Status) { paymentsFlowTracker.trackReceiptViewTapped( mapOf( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt index 29c4c43cc75..25c43d20146 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailViewModel.kt @@ -34,6 +34,8 @@ import com.woocommerce.android.tools.ProductImageMap import com.woocommerce.android.tools.ProductImageMap.OnProductFetchedListener import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.common.giftcard.GiftCardRepository +import com.woocommerce.android.ui.orders.CurrencyMatchResult +import com.woocommerce.android.ui.orders.IsStoreCurrencyMatch import com.woocommerce.android.ui.orders.OrderNavigationTarget import com.woocommerce.android.ui.orders.OrderNavigationTarget.AddOrderNote import com.woocommerce.android.ui.orders.OrderNavigationTarget.AddOrderShipmentTracking @@ -116,6 +118,7 @@ class OrderDetailViewModel @Inject constructor( private val paymentReceiptHelper: PaymentReceiptHelper, private val analyticsTracker: AnalyticsTrackerWrapper, private val refreshShippingMethods: RefreshShippingMethods, + private val isStoreCurrencyMatch: IsStoreCurrencyMatch, getShippingMethodsWithOtherValue: GetShippingMethodsWithOtherValue ) : ScopedViewModel(savedState), OnProductFetchedListener { private val navArgs: OrderDetailFragmentArgs by savedState.navArgs() @@ -371,6 +374,17 @@ class OrderDetailViewModel @Inject constructor( } fun onEditClicked() { + launch { + val isCurrencyMatch = isStoreCurrencyMatch(order.currency) + if (!isCurrencyMatch.isMatch) { + handleEditClickWhenCurrencyMismatch(isCurrencyMatch) + } else { + handleEditClick() + } + } + } + + private fun handleEditClick() { tracker.trackEditButtonTapped(order.feesLines.size, order.shippingLines.size) val firstGiftCard = giftCards.value?.firstOrNull() triggerEvent( @@ -382,6 +396,16 @@ class OrderDetailViewModel @Inject constructor( ) } + private fun handleEditClickWhenCurrencyMismatch(isCurrencyMatch: CurrencyMatchResult) { + tracker.trackOrderAndStoreCurrencyMismatchWhenEditButtonTapped() + triggerEvent( + ShowSnackbar( + message = string.order_detail_edit_store_currency_mismatch, + args = arrayOf(order.currency, isCurrencyMatch.storeCurrency.orEmpty()) + ) + ) + } + fun orderNavigationIsEnabled() = navArgs.allOrderIds?.let { it.contains(navArgs.orderId) && it.count() > 1 } ?: false diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/views/OrderDetailCustomerInfoView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/views/OrderDetailCustomerInfoView.kt index afdf4f10cc1..d2290ec4e14 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/views/OrderDetailCustomerInfoView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/views/OrderDetailCustomerInfoView.kt @@ -240,11 +240,7 @@ class OrderDetailCustomerInfoView @JvmOverloads constructor( ) binding.customerInfoCustomerNoteSection.setOnClickListener { - val action = - OrderDetailFragmentDirections.actionOrderDetailFragmentToEditCustomerOrderNoteFragment( - order.id - ) - findNavController().navigateSafely(action) + navigateToCustomerNote(order) } } } @@ -290,13 +286,26 @@ class OrderDetailCustomerInfoView @JvmOverloads constructor( } } + private fun navigateToCustomerNote(order: Order) { + if (!isAttachedToWindow) return + + val action = OrderDetailFragmentDirections.actionOrderDetailFragmentToEditCustomerOrderNoteFragment( + order.id + ) + findNavController().navigateSafely(action) + } + private fun navigateToShippingAddressEditingView(address: Address) { + if (!isAttachedToWindow) return + OrderDetailFragmentDirections .actionOrderDetailFragmentToShippingAddressEditingFragment(storedAddress = address) .let { findNavController().navigateSafely(it) } } private fun navigateToBillingAddressEditingView(address: Address) { + if (!isAttachedToWindow) return + OrderDetailFragmentDirections .actionOrderDetailFragmentToBillingAddressEditingFragment(storedAddress = address) .let { findNavController().navigateSafely(it) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelFragment.kt index a1bbfb248c4..1a5bd6b8f8c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelFragment.kt @@ -67,6 +67,7 @@ class PrintShippingLabelFragment : BaseFragment(R.layout.fragment_print_shipping private fun setupToolbar(binding: FragmentPrintShippingLabelBinding) { binding.toolbar.title = getString(viewModel.screenTitle) binding.toolbar.setNavigationOnClickListener { + @Suppress("DEPRECATION") when { requireContext().windowSizeClass != WindowSizeClass.Compact && onRequestAllowBackPress() -> { findNavController().navigateUp() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/PurchaseSection.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/PurchaseSection.kt index 07651bdc9cc..c52d302a23f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/PurchaseSection.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/PurchaseSection.kt @@ -23,6 +23,7 @@ internal fun PurchasesSection( total: String?, markOrderComplete: Boolean, onMarkOrderCompleteChange: (Boolean) -> Unit, + onPurchaseShippingLabel: () -> Unit, modifier: Modifier = Modifier ) { Column(modifier) { @@ -31,7 +32,7 @@ internal fun PurchasesSection( markOrderComplete = markOrderComplete, onMarkOrderCompleteChange = onMarkOrderCompleteChange ) - PurchaseButton(total) + PurchaseButton(total, onPurchaseShippingLabel) } } @@ -40,6 +41,7 @@ internal fun PurchasesSectionLandscape( total: String?, markOrderComplete: Boolean, onMarkOrderCompleteChange: (Boolean) -> Unit, + onPurchaseShippingLabel: () -> Unit, modifier: Modifier = Modifier ) { Column(modifier.fillMaxWidth()) { @@ -50,7 +52,11 @@ internal fun PurchasesSectionLandscape( onMarkOrderCompleteChange = onMarkOrderCompleteChange, modifier = Modifier.weight(1f) ) - PurchaseButton(total = total, modifier = Modifier.weight(1f)) + PurchaseButton( + total = total, + onPurchaseShippingLabel = onPurchaseShippingLabel, + modifier = Modifier.weight(1f) + ) } } } @@ -63,6 +69,7 @@ fun PurchasesSectionLandscapePreview() { total = "$12.00", markOrderComplete = true, onMarkOrderCompleteChange = {}, + onPurchaseShippingLabel = {}, modifier = Modifier.padding(dimensionResource(R.dimen.major_100)) ) } @@ -97,13 +104,14 @@ private fun MarkComplete( @Composable private fun PurchaseButton( total: String?, + onPurchaseShippingLabel: () -> Unit, modifier: Modifier = Modifier ) { val buttonText = total?.let { stringResource(id = R.string.shipping_label_shipment_details_purchase_label, it) } ?: stringResource(id = R.string.shipping_label_shipment_details_purchase_label_disabled) WCColoredButton( - onClick = { }, + onClick = { onPurchaseShippingLabel() }, enabled = total != null, text = buttonText, modifier = modifier @@ -125,6 +133,7 @@ private fun PurchasesSectionPreview() { total = null, markOrderComplete = true, onMarkOrderCompleteChange = {}, + onPurchaseShippingLabel = {}, modifier = Modifier.padding(dimensionResource(R.dimen.major_100)) ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/ShipmentDetails.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/ShipmentDetails.kt index 76149fb342a..6895ddc841c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/ShipmentDetails.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/ShipmentDetails.kt @@ -55,6 +55,7 @@ fun ShipmentDetails( scaffoldState: BottomSheetScaffoldState, markOrderComplete: Boolean, onMarkOrderCompleteChange: (Boolean) -> Unit, + onPurchaseShippingLabel: () -> Unit, modifier: Modifier = Modifier, ) { val scope = rememberCoroutineScope() @@ -91,12 +92,14 @@ fun ShipmentDetails( if (LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE) { ShipmentDetailsLandscape( markOrderComplete = markOrderComplete, - onMarkOrderCompleteChange = onMarkOrderCompleteChange + onMarkOrderCompleteChange = onMarkOrderCompleteChange, + onPurchaseShippingLabel = onPurchaseShippingLabel ) } else { ShipmentDetailsPortrait( markOrderComplete = markOrderComplete, - onMarkOrderCompleteChange = onMarkOrderCompleteChange + onMarkOrderCompleteChange = onMarkOrderCompleteChange, + onPurchaseShippingLabel = onPurchaseShippingLabel ) } } @@ -105,6 +108,7 @@ fun ShipmentDetails( private fun ShipmentDetailsPortrait( markOrderComplete: Boolean, onMarkOrderCompleteChange: (Boolean) -> Unit, + onPurchaseShippingLabel: () -> Unit, modifier: Modifier = Modifier, ) { Column(modifier) { @@ -133,7 +137,8 @@ private fun ShipmentDetailsPortrait( PurchasesSection( total = "$120.99", markOrderComplete = markOrderComplete, - onMarkOrderCompleteChange = onMarkOrderCompleteChange + onMarkOrderCompleteChange = onMarkOrderCompleteChange, + onPurchaseShippingLabel = onPurchaseShippingLabel ) } } @@ -142,6 +147,7 @@ private fun ShipmentDetailsPortrait( private fun ShipmentDetailsLandscape( markOrderComplete: Boolean, onMarkOrderCompleteChange: (Boolean) -> Unit, + onPurchaseShippingLabel: () -> Unit, modifier: Modifier = Modifier, ) { Column(modifier) { @@ -158,7 +164,11 @@ private fun ShipmentDetailsLandscape( shipTo = getShipTo(), modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.major_100)) ) - Row(modifier = Modifier.height(IntrinsicSize.Min).fillMaxWidth()) { + Row( + modifier = Modifier + .height(IntrinsicSize.Min) + .fillMaxWidth() + ) { OrderDetailsSectionLandscape( totalItems = 5, totalItemsCost = "$120.99", @@ -178,7 +188,8 @@ private fun ShipmentDetailsLandscape( PurchasesSectionLandscape( total = "$120.99", markOrderComplete = markOrderComplete, - onMarkOrderCompleteChange = onMarkOrderCompleteChange + onMarkOrderCompleteChange = onMarkOrderCompleteChange, + onPurchaseShippingLabel = onPurchaseShippingLabel ) } } @@ -264,7 +275,8 @@ fun ShipmentDetailsLandscapePreview() { Surface { ShipmentDetailsLandscape( markOrderComplete = false, - onMarkOrderCompleteChange = {} + onMarkOrderCompleteChange = {}, + onPurchaseShippingLabel = {} ) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt index 14d729685e1..8c5b6ea2ac8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt @@ -47,6 +47,15 @@ class WooShippingLabelCreationFragment : BaseFragment() { WooShippingLabelCreationFragmentDirections .actionWooShippingLabelCreationFragmentToWooShippingLabelPackageCreationFragment() .let { findNavController().navigateSafely(it) } + + is WooShippingLabelCreationViewModel.LabelPurchased -> { + WooShippingLabelCreationFragmentDirections + .actionWooShippingLabelCreationFragmentToWooShippingLabelPurchasedFragment() + .let { + val navController = findNavController() + navController.navigateSafely(it) + } + } } } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationScreen.kt index 0947976fdf0..f9957397635 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationScreen.kt @@ -44,7 +44,8 @@ import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground @Composable fun WooShippingLabelCreationScreen(viewModel: WooShippingLabelCreationViewModel) { WooShippingLabelCreationScreen( - onSelectPackageClick = viewModel::onSelectPackageClicked + onSelectPackageClick = viewModel::onSelectPackageClicked, + onPurchaseShippingLabel = viewModel::onPurchaseShippingLabel ) } @@ -52,7 +53,8 @@ fun WooShippingLabelCreationScreen(viewModel: WooShippingLabelCreationViewModel) @Composable fun WooShippingLabelCreationScreen( modifier: Modifier = Modifier, - onSelectPackageClick: () -> Unit + onSelectPackageClick: () -> Unit, + onPurchaseShippingLabel: () -> Unit ) { val scaffoldState = rememberBottomSheetScaffoldState() BottomSheetScaffold( @@ -61,7 +63,8 @@ fun WooShippingLabelCreationScreen( ShipmentDetails( scaffoldState = scaffoldState, markOrderComplete = markOrderComplete.value, - onMarkOrderCompleteChange = { markOrderComplete.value = it } + onMarkOrderCompleteChange = { markOrderComplete.value = it }, + onPurchaseShippingLabel = onPurchaseShippingLabel ) }, sheetPeekHeight = 64.dp, @@ -139,13 +142,14 @@ private fun WooShippingLabelCreationScreenPreview() { WooThemeWithBackground { WooShippingLabelCreationScreen( modifier = Modifier.fillMaxSize(), - onSelectPackageClick = {} + onSelectPackageClick = {}, + onPurchaseShippingLabel = {} ) } } @Composable -private fun HazmatCard( +internal fun HazmatCard( modifier: Modifier = Modifier, onClick: () -> Unit = {} ) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationViewModel.kt index 4c7eb230ddd..50d3b43c5e2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationViewModel.kt @@ -11,6 +11,8 @@ class WooShippingLabelCreationViewModel @Inject constructor( savedState: SavedStateHandle ) : ScopedViewModel(savedState) { fun onSelectPackageClicked() { triggerEvent(StartPackageSelection) } + fun onPurchaseShippingLabel() { triggerEvent(LabelPurchased) } data object StartPackageSelection : Event() + data object LabelPurchased : Event() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingProductsCard.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingProductsCard.kt index 8c4149b1ebf..b6011e30a2e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingProductsCard.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingProductsCard.kt @@ -49,6 +49,7 @@ import com.woocommerce.android.util.StringUtils fun ShippingProductsCard( shippableItems: ShippableItems, modifier: Modifier = Modifier, + iconColor: Color = MaterialTheme.colors.primary, isExpanded: Boolean = false, onExpand: (Boolean) -> Unit = {} ) { @@ -58,6 +59,7 @@ fun ShippingProductsCard( ShippingProductsCardHeader( shippableItems = shippableItems, isExpanded = isExpanded, + iconColor = iconColor, modifier = Modifier .clip(RoundedCornerShape(dimensionResource(R.dimen.corner_radius_large))) .clickable { onExpand(!isExpanded) } @@ -96,6 +98,7 @@ private fun ShippingProductsCardPreview(@PreviewParameter(IsExpandedProvider::cl @Composable private fun ShippingProductsCardHeader( shippableItems: ShippableItems, + iconColor: Color, modifier: Modifier = Modifier, isExpanded: Boolean = false ) { @@ -155,7 +158,7 @@ private fun ShippingProductsCardHeader( ) Icon( painter = painterResource(R.drawable.ic_arrow_down), - tint = MaterialTheme.colors.primary, + tint = iconColor, contentDescription = stringResource(id = R.string.shipping_label_package_details_items_expand_content_description), modifier = Modifier @@ -182,6 +185,7 @@ private fun ShippingProductsCardHeaderPreview() { ShippingProductsCardHeader( shippableItems = shippableItems, isExpanded = isExpanded.value, + iconColor = MaterialTheme.colors.primary, modifier = Modifier .clickable { isExpanded.value = !isExpanded.value } .padding( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/Models.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/Models.kt new file mode 100644 index 00000000000..0e6336662b6 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/Models.kt @@ -0,0 +1,84 @@ +package com.woocommerce.android.ui.orders.wooshippinglabels.packages + +import android.os.Parcelable +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageType +import kotlinx.parcelize.Parcelize + +@Parcelize +data class PackageData( + val type: PackageType, + val name: String, + val description: String, + val length: String, + val width: String, + val height: String, + val isSelected: Boolean, + val dimensionUnit: String = "cm" +) : Parcelable { + val dimensionsForDisplay: String + get() = "$length x $width x $height $dimensionUnit" +} + +@Parcelize +data class CarrierPackageGroup( + val groupName: String, + val packages: List +) : Parcelable + +@Parcelize +data class Carrier( + val id: String, + val name: String, + val logoRes: Int? = null, +) : Parcelable + +@Parcelize +data class CarrierPackageSelection( + val carrierPackages: Map> +) : Parcelable { + val hasSelection: Boolean + get() = carrierPackages.values.flatten().find { group -> + group.packages.find { it.isSelected } != null + } != null +} + +@Parcelize +data class SavedPackageSelection( + val packages: List +) : Parcelable { + val hasSelection: Boolean + get() = packages.find { it.isSelected } != null +} + +@Parcelize +data class CustomPackageCreationData( + val type: PackageType, + val length: String, + val width: String, + val height: String, + val saveAsTemplate: Boolean +) : Parcelable { + val isValid: Boolean + get() = height.isNotEmpty() && length.isNotEmpty() && width.isNotEmpty() + + val asPackageData: PackageData + get() = PackageData( + type = type, + name = "", + description = "", + length = length, + width = width, + height = height, + isSelected = true + ) + + companion object { + val EMPTY = CustomPackageCreationData( + type = PackageType.BOX, + length = "", + width = "", + height = "", + saveAsTemplate = false + ) + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationFragment.kt index 25676ccff35..8f6391eab0c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationFragment.kt @@ -6,9 +6,17 @@ import android.view.View import android.view.ViewGroup import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed +import androidx.fragment.app.setFragmentResult import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import com.woocommerce.android.R +import com.woocommerce.android.extensions.handleDialogResult +import com.woocommerce.android.extensions.navigateSafely import com.woocommerce.android.ui.base.BaseFragment import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageSelected +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageType +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.ShowPackageTypeDialog import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -25,4 +33,54 @@ class WooShippingLabelPackageCreationFragment : BaseFragment() { } } } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + bindEventListener() + bindResultHandlers() + } + + private fun bindEventListener() { + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowPackageTypeDialog -> handlePackageTypeSelection(event.currentSelection) + is PackageSelected -> handlePackageDataAsResult(event.packageData) + } + } + } + + private fun bindResultHandlers() { + handleDialogResult( + key = SELECTOR_REQUEST_KEY, + entryId = R.id.wooShippingLabelPackageCreationFragment + ) { result -> + PackageType.entries + .firstOrNull { it.toString() == result } + ?.let { viewModel.onPackageTypeSelected(it) } + } + } + + private fun handlePackageTypeSelection(currentSelection: PackageType) { + WooShippingLabelPackageCreationFragmentDirections + .actionWooShippingLabelPackageCreationFragmentToItemSelectorDialog( + requestKey = SELECTOR_REQUEST_KEY, + selectedItem = currentSelection.name, + values = PackageType.entries.map { it.name }.toTypedArray(), + keys = PackageType.entries + .map { getString(it.resourceId) } + .toTypedArray() + ).let { findNavController().navigateSafely(it) } + } + + private fun handlePackageDataAsResult(packageData: PackageData) { + setFragmentResult( + PACKAGE_SELECTION_RESULT, + Bundle().apply { putParcelable(PACKAGE_SELECTION_RESULT, packageData) } + ) + } + + companion object { + const val SELECTOR_REQUEST_KEY = "package_type" + const val PACKAGE_SELECTION_RESULT = "package_selection" + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationScreen.kt index a2e2d91c9b4..24c9826facc 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationScreen.kt @@ -6,8 +6,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold import androidx.compose.material.Tab @@ -23,6 +21,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageType import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PageTab import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PageType.CARRIER import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PageType.CUSTOM @@ -39,8 +38,8 @@ fun WooShippingLabelPackageCreationScreen( WooShippingLabelPackageCreationScreen( tabs = viewState.value?.pageTabs.orEmpty(), createCustomPackageScreen = { WooShippingCustomPackageCreationScreen(viewModel) }, - createCarrierPackageScreen = { WooShippingCarrierPackageScreen() }, - createSavedPackageScreen = { WooShippingSavedPackageScreen() } + createCarrierPackageScreen = { WooShippingCarrierPackageScreen(viewModel) }, + createSavedPackageScreen = { WooShippingSavedPackageScreen(viewModel) } ) } @@ -66,9 +65,13 @@ fun WooShippingLabelPackageCreationScreen( Scaffold( topBar = { - TabRow(selectedTabIndex = tabIndex) { + TabRow( + selectedTabIndex = tabIndex, + backgroundColor = MaterialTheme.colors.surface, + ) { tabs.forEachIndexed { index, pageTab -> Tab( + selectedContentColor = MaterialTheme.colors.onSurface, text = { Text(text = pageTab.title) }, selected = tabIndex == index, onClick = { tabIndex = index } @@ -83,7 +86,6 @@ fun WooShippingLabelPackageCreationScreen( .background(MaterialTheme.colors.surface) .padding(paddingValues) .fillMaxSize() - .verticalScroll(rememberScrollState()) ) { currentPageIndex -> when (tabs[currentPageIndex].type) { CUSTOM -> createCustomPackageScreen() @@ -120,8 +122,43 @@ fun WooShippingLabelsPackageCreationScreenPreview() { onSavePackageChanged = { } ) }, - createCarrierPackageScreen = { }, - createSavedPackageScreen = { } + createSavedPackageScreen = { + WooShippingSavedPackageScreen( + savedPackages = listOf( + PackageData( + type = PackageType.ENVELOPE, + name = "Small Flat Rate Box", + description = "USPS Priority Mail Flat Rate Boxes", + length = "10", + width = "10", + height = "10", + isSelected = true + ), + PackageData( + type = PackageType.BOX, + name = "Small Flat Rate Box", + description = "Custom package", + length = "20", + width = "20", + height = "20", + isSelected = false + ), + PackageData( + type = PackageType.BOX, + name = "Small Flat Rate Box", + description = "DHL Express", + length = "30", + width = "30", + height = "30", + isSelected = false + ) + ), + isAddPackageEnabled = true, + onAddPackageClick = { }, + onSavedPackageSelected = { _, _ -> } + ) + }, + createCarrierPackageScreen = { } ) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModel.kt index 836d69570c1..5b90808d7e3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModel.kt @@ -5,6 +5,8 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import com.woocommerce.android.R +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.FetchCarrierPackagesFromStore +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.FetchSavedPackagesFromStore import com.woocommerce.android.viewmodel.MultiLiveEvent import com.woocommerce.android.viewmodel.ResourceProvider import com.woocommerce.android.viewmodel.ScopedViewModel @@ -17,12 +19,14 @@ import javax.inject.Inject @HiltViewModel class WooShippingLabelPackageCreationViewModel @Inject constructor( savedState: SavedStateHandle, - private val resourceProvider: ResourceProvider + private val resourceProvider: ResourceProvider, + private val fetchSavedPackages: FetchSavedPackagesFromStore, + private val fetchCarrierPackages: FetchCarrierPackagesFromStore ) : ScopedViewModel(savedState) { private val _viewState = savedState.getStateFlow( scope = viewModelScope, - initialValue = ViewState(pageTabs, CustomPackageCreationData.EMPTY) + initialValue = ViewState(pageTabs) ) val viewState = _viewState.asLiveData() @@ -42,8 +46,52 @@ class WooShippingLabelPackageCreationViewModel @Inject constructor( ) ) - fun onAddPackageClick() { - triggerEvent(PackageSelected(_viewState.value.customPackageCreationData)) + init { + _viewState.update { viewState -> + viewState.copy( + savedPackageSelection = SavedPackageSelection(fetchSavedPackages()), + carrierPackageSection = CarrierPackageSelection(fetchCarrierPackages()) + ) + } + } + + fun onCarrierPackageSelected(selectedPackage: PackageData, isSelected: Boolean) { + _viewState.update { viewState -> + viewState.carrierPackageSection.carrierPackages + .map { updateCarrierPackagesSelection(it, selectedPackage, isSelected) } + .let { viewState.copy(carrierPackageSection = CarrierPackageSelection(it.toMap())) } + } + } + + fun onSavedPackageSelected(selectedPackage: PackageData, isSelected: Boolean) { + _viewState.update { viewState -> + viewState.savedPackageSelection.packages + .map { it.copy(isSelected = false) } + .toMutableList() + .safelyUpdate(selectedPackage, selectedPackage.copy(isSelected = isSelected)) + .let { SavedPackageSelection(it) } + .let { viewState.copy(savedPackageSelection = it) } + } + } + + fun onAddCarrierPackageClick() { + _viewState.value.carrierPackageSection.carrierPackages + .asSequence() + .flatMap { it.value } + .flatMap { it.packages } + .find { it.isSelected } + ?.let { triggerEvent(PackageSelected(it)) } + } + + fun onAddSavedPackageClick() { + _viewState.value.savedPackageSelection.packages.find { it.isSelected } + ?.let { triggerEvent(PackageSelected(it)) } + } + + fun onAddCustomPackageClick() { + _viewState.value.customPackageCreationData + .asPackageData + .let { triggerEvent(PackageSelected(it)) } } fun onPackageTypeSpinnerClick() { @@ -85,10 +133,33 @@ class WooShippingLabelPackageCreationViewModel @Inject constructor( } } + private fun updateCarrierPackagesSelection( + carrierPackages: Map.Entry>, + packageData: PackageData, + isSelected: Boolean + ) = carrierPackages.value.map { packageGroup -> + packageGroup.packages + .map { it.copy(isSelected = false) } + .toMutableList() + .safelyUpdate(packageData, packageData.copy(isSelected = isSelected)) + .let { packageGroup.copy(packages = it) } + }.let { carrierPackages.key to it } + + private fun MutableList.safelyUpdate( + originalPackage: PackageData, + updatedPackage: PackageData + ) = apply { + indexOf(originalPackage) + .takeIf { it != -1 } + ?.let { set(it, updatedPackage) } + } + @Parcelize data class ViewState( val pageTabs: List = emptyList(), - val customPackageCreationData: CustomPackageCreationData + val customPackageCreationData: CustomPackageCreationData = CustomPackageCreationData.EMPTY, + val savedPackageSelection: SavedPackageSelection = SavedPackageSelection(emptyList()), + val carrierPackageSection: CarrierPackageSelection = CarrierPackageSelection(emptyMap()) ) : Parcelable @Parcelize @@ -97,28 +168,6 @@ class WooShippingLabelPackageCreationViewModel @Inject constructor( val type: PageType ) : Parcelable - @Parcelize - data class CustomPackageCreationData( - val type: PackageType, - val length: String, - val width: String, - val height: String, - val saveAsTemplate: Boolean - ) : Parcelable { - val isValid: Boolean - get() = height.isNotEmpty() && length.isNotEmpty() && width.isNotEmpty() - - companion object { - val EMPTY = CustomPackageCreationData( - type = PackageType.BOX, - length = "", - width = "", - height = "", - saveAsTemplate = false - ) - } - } - enum class PageType { CUSTOM, CARRIER, @@ -130,6 +179,6 @@ class WooShippingLabelPackageCreationViewModel @Inject constructor( ENVELOPE(R.string.woo_shipping_labels_package_creation_envelope_type) } - data class PackageSelected(val packageData: CustomPackageCreationData) : MultiLiveEvent.Event() + data class PackageSelected(val packageData: PackageData) : MultiLiveEvent.Event() data class ShowPackageTypeDialog(val currentSelection: PackageType) : MultiLiveEvent.Event() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/components/WooShippingPackageListItem.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/components/WooShippingPackageListItem.kt new file mode 100644 index 00000000000..8cc58273b7f --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/components/WooShippingPackageListItem.kt @@ -0,0 +1,58 @@ +package com.woocommerce.android.ui.orders.wooshippinglabels.packages.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Divider +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.unit.dp +import com.woocommerce.android.R +import com.woocommerce.android.ui.compose.component.SelectionCheck +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.PackageData + +@Composable +fun WooSavedPackageListItem( + modifier: Modifier, + packageData: PackageData, + onPackageSelected: (PackageData, Boolean) -> Unit +) { + Column( + modifier = modifier + .clickable { onPackageSelected(packageData, packageData.isSelected.not()) } + .padding(top = 8.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + SelectionCheck( + isSelected = packageData.isSelected, + onSelectionChange = { onPackageSelected(packageData, it) } + ) + Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { + Text( + text = packageData.description, + style = MaterialTheme.typography.caption, + color = colorResource(id = R.color.color_on_surface_disabled) + ) + Text( + text = packageData.name, + style = MaterialTheme.typography.body1 + ) + Text( + text = packageData.dimensionsForDisplay, + style = MaterialTheme.typography.body2 + ) + } + } + Divider() + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchCarrierPackagesFromStore.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchCarrierPackagesFromStore.kt new file mode 100644 index 00000000000..2ee95f8bfad --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchCarrierPackagesFromStore.kt @@ -0,0 +1,99 @@ +package com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource + +import com.woocommerce.android.R +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.Carrier +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.CarrierPackageGroup +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.PackageData +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageType +import javax.inject.Inject + +class FetchCarrierPackagesFromStore @Inject constructor() { + @Suppress("LongMethod") + operator fun invoke(): Map> { + // This is a mocked response. + // When fully implemented, this will be sorted from the Shipping plugin API. + return mapOf( + Carrier( + id = "dhl", + name = "DHL Express", + logoRes = R.drawable.dhl_logo + ) to listOf( + CarrierPackageGroup( + groupName = "Group 1", + packages = listOf( + PackageData( + type = PackageType.BOX, + name = "Package 1 - Carrier 1", + description = "Description 1", + length = "10", + width = "10", + height = "10", + isSelected = false + ), + PackageData( + type = PackageType.BOX, + name = "Package 2 - Carrier 1", + description = "Description 2", + length = "20", + width = "20", + height = "20", + isSelected = false + ) + ) + ), + CarrierPackageGroup( + groupName = "Group 2", + packages = listOf( + PackageData( + type = PackageType.BOX, + name = "Package 3 - Carrier 1", + description = "Description 3", + length = "30", + width = "30", + height = "30", + isSelected = false + ), + PackageData( + type = PackageType.BOX, + name = "Package 4 - Carrier 1", + description = "Description 4", + length = "40", + width = "40", + height = "40", + isSelected = false + ) + ) + ) + ), + Carrier( + id = "usps", + name = "USPS", + logoRes = R.drawable.usps_logo + ) to listOf( + CarrierPackageGroup( + groupName = "Group 2", + packages = listOf( + PackageData( + type = PackageType.BOX, + name = "Package 1 - Carrier 2", + description = "Description 1", + length = "10", + width = "10", + height = "10", + isSelected = false + ), + PackageData( + type = PackageType.BOX, + name = "Package 2 Carrier - 2", + description = "Description 2", + length = "20", + width = "20", + height = "20", + isSelected = false + ) + ) + ) + ) + ) + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchSavedPackagesFromStore.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchSavedPackagesFromStore.kt new file mode 100644 index 00000000000..e229047f956 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchSavedPackagesFromStore.kt @@ -0,0 +1,41 @@ +package com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource + +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.PackageData +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageType +import javax.inject.Inject + +class FetchSavedPackagesFromStore @Inject constructor() { + operator fun invoke(): List { + // This is a mocked response. + // When fully implemented, this will be sorted from the Shipping plugin API. + return listOf( + PackageData( + type = PackageType.ENVELOPE, + name = "Small Flat Rate Box", + description = "USPS Priority Mail Flat Rate Boxes", + length = "10", + width = "10", + height = "10", + isSelected = true + ), + PackageData( + type = PackageType.BOX, + name = "Small Flat Rate Box", + description = "Custom package", + length = "20", + width = "20", + height = "20", + isSelected = false + ), + PackageData( + type = PackageType.BOX, + name = "Small Flat Rate Box", + description = "DHL Express", + length = "30", + width = "30", + height = "30", + isSelected = false + ) + ) + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingCarrierPackageScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingCarrierPackageScreen.kt index f27f782dbce..35fdb3027a8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingCarrierPackageScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingCarrierPackageScreen.kt @@ -1,9 +1,317 @@ package com.woocommerce.android.ui.orders.wooshippinglabels.packages.forms +import androidx.annotation.DrawableRes +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.PagerState +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.Divider +import androidx.compose.material.Icon +import androidx.compose.material.LeadingIconTab +import androidx.compose.material.MaterialTheme +import androidx.compose.material.ScrollableTabRow import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.woocommerce.android.R +import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.Carrier +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.CarrierPackageGroup +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.PackageData +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageType +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.components.WooSavedPackageListItem +import kotlinx.coroutines.launch @Composable -fun WooShippingCarrierPackageScreen() { - Text("Carrier Package Form") +fun WooShippingCarrierPackageScreen(viewModel: WooShippingLabelPackageCreationViewModel) { + val viewState by viewModel.viewState.observeAsState() + WooShippingCarrierPackageScreen( + carrierPackages = viewState?.carrierPackageSection?.carrierPackages ?: emptyMap(), + isAddPackageEnabled = viewState?.carrierPackageSection?.hasSelection ?: false, + onPackageSelected = viewModel::onCarrierPackageSelected, + onAddPackageClick = viewModel::onAddCarrierPackageClick + ) +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun WooShippingCarrierPackageScreen( + modifier: Modifier = Modifier, + carrierPackages: Map>, + onPackageSelected: (PackageData, Boolean) -> Unit, + isAddPackageEnabled: Boolean = false, + onAddPackageClick: () -> Unit = {} +) { + val pagerState = rememberPagerState { carrierPackages.keys.size } + Column( + modifier = modifier + .fillMaxSize() + .background(MaterialTheme.colors.surface) + ) { + CarrierTabRow( + modifier = modifier, + pagerState = pagerState, + carriers = carrierPackages.keys.toList() + ) + PackageListPager( + modifier = modifier + .weight(1f), + pagerState = pagerState, + carrierPackages = carrierPackages, + onPackageSelected = onPackageSelected + ) + Divider() + Button( + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp), + enabled = isAddPackageEnabled, + onClick = onAddPackageClick + ) { + Text(stringResource(id = R.string.woo_shipping_labels_package_creation_add_package)) + } + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +private fun CarrierTabRow( + modifier: Modifier, + pagerState: PagerState, + carriers: List +) { + val scope = rememberCoroutineScope() + ScrollableTabRow( + modifier = modifier.fillMaxWidth(), + selectedTabIndex = pagerState.currentPage, + edgePadding = dimensionResource(R.dimen.major_100), + backgroundColor = MaterialTheme.colors.surface, + contentColor = MaterialTheme.colors.primary, + ) { + carriers.forEachIndexed { index, carrier -> + val textColor = if (index == pagerState.currentPage) { + MaterialTheme.colors.primary + } else { + colorResource(id = R.color.color_on_surface_medium) + } + LeadingIconTab( + text = { + Text( + text = carrier.name, + color = textColor, + style = MaterialTheme.typography.subtitle2 + ) + }, + icon = { + carrier.logoRes?.let { CarrierLogo(it) } + }, + selected = pagerState.currentPage == index, + onClick = { + scope.launch { + pagerState.animateScrollToPage(index) + } + } + ) + } + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +private fun PackageListPager( + modifier: Modifier, + pagerState: PagerState, + carrierPackages: Map>, + onPackageSelected: (PackageData, Boolean) -> Unit +) { + HorizontalPager( + state = pagerState, + modifier = modifier.fillMaxWidth(), + verticalAlignment = Alignment.Top + ) { page -> + val carrierForPageIndex = carrierPackages.keys.toList()[page] + val carrierPackageGroups = carrierPackages[carrierForPageIndex] ?: emptyList() + PackageList( + packageGroups = carrierPackageGroups, + onPackageSelected = onPackageSelected + ) + } +} + +@Composable +private fun PackageList( + packageGroups: List, + onPackageSelected: (PackageData, Boolean) -> Unit +) { + Column(modifier = Modifier.fillMaxSize()) { + packageGroups.forEach { group -> + Spacer(modifier = Modifier.height(8.dp)) + PackageListSection( + sectionHeader = group.groupName, + packages = group.packages, + onPackageSelected = onPackageSelected + ) + } + } +} + +@Composable +private fun PackageListSection( + sectionHeader: String, + packages: List, + onPackageSelected: (PackageData, Boolean) -> Unit +) { + Column( + modifier = Modifier + .padding(start = 8.dp) + .wrapContentHeight(), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = sectionHeader, + style = MaterialTheme.typography.body1, + color = colorResource(id = R.color.color_on_surface_disabled) + ) + Divider() + packages.forEach { packageData -> + WooSavedPackageListItem( + modifier = Modifier.padding(start = 16.dp), + packageData = packageData, + onPackageSelected = onPackageSelected + ) + } + } +} + +@Composable +private fun CarrierLogo( + @DrawableRes resId: Int, + modifier: Modifier = Modifier +) { + Icon( + painter = painterResource(id = resId), + contentDescription = null, + modifier = modifier + .size(24.dp) + .clip(RoundedCornerShape(5.dp)), + tint = Color.Unspecified + ) +} + +@Preview +@Composable +fun WooShippingCarrierPackageScreenPreview() { + WooThemeWithBackground { + WooShippingCarrierPackageScreen( + carrierPackages = mapOf( + Carrier( + id = "dhl", + name = "DHL Express", + logoRes = R.drawable.dhl_logo + ) to listOf( + CarrierPackageGroup( + groupName = "Group 1", + packages = listOf( + PackageData( + type = PackageType.BOX, + name = "Package 1 - Carrier 1", + description = "Description 1", + length = "10", + width = "10", + height = "10", + isSelected = false + ), + PackageData( + type = PackageType.BOX, + name = "Package 2 - Carrier 1", + description = "Description 2", + length = "20", + width = "20", + height = "20", + isSelected = false + ) + ) + ), + CarrierPackageGroup( + groupName = "Group 2", + packages = listOf( + PackageData( + type = PackageType.BOX, + name = "Package 3 - Carrier 1", + description = "Description 3", + length = "30", + width = "30", + height = "30", + isSelected = false + ), + PackageData( + type = PackageType.BOX, + name = "Package 4 - Carrier 1", + description = "Description 4", + length = "40", + width = "40", + height = "40", + isSelected = false + ) + ) + ) + ), + Carrier( + id = "usps", + name = "USPS", + logoRes = R.drawable.usps_logo + ) to listOf( + CarrierPackageGroup( + groupName = "Group 2", + packages = listOf( + PackageData( + type = PackageType.BOX, + name = "Package 1 - Carrier 2", + description = "Description 1", + length = "10", + width = "10", + height = "10", + isSelected = false + ), + PackageData( + type = PackageType.BOX, + name = "Package 2 Carrier - 2", + description = "Description 2", + length = "20", + width = "20", + height = "20", + isSelected = false + ) + ) + ) + ) + ), + onPackageSelected = { _, _ -> } + ) + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingCustomPackageScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingCustomPackageScreen.kt index 8240ffada01..83bcb39f439 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingCustomPackageScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingCustomPackageScreen.kt @@ -6,7 +6,9 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll import androidx.compose.material.Button import androidx.compose.material.Checkbox import androidx.compose.material.Text @@ -37,7 +39,7 @@ fun WooShippingCustomPackageCreationScreen(viewModel: WooShippingLabelPackageCre packageLength = viewState?.customPackageCreationData?.length.orEmpty(), packageWidth = viewState?.customPackageCreationData?.width.orEmpty(), isAddPackageEnabled = viewState?.customPackageCreationData?.isValid ?: false, - onAddPackageClick = viewModel::onAddPackageClick, + onAddPackageClick = viewModel::onAddCustomPackageClick, onPackageTypeClick = viewModel::onPackageTypeSpinnerClick, onLengthChange = viewModel::onLengthChange, onWidthChange = viewModel::onWidthChange, @@ -65,6 +67,7 @@ fun WooShippingCustomPackageCreationScreen( modifier = modifier .fillMaxSize() .padding(16.dp) + .verticalScroll(rememberScrollState()) ) { Column( modifier = modifier.weight(1f), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingSavedPackageScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingSavedPackageScreen.kt index 120209e5dfa..54e3517c551 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingSavedPackageScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/forms/WooShippingSavedPackageScreen.kt @@ -1,9 +1,117 @@ package com.woocommerce.android.ui.orders.wooshippinglabels.packages.forms +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Button +import androidx.compose.material.Divider import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.woocommerce.android.R +import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.PackageData +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageType +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.components.WooSavedPackageListItem @Composable -fun WooShippingSavedPackageScreen() { - Text("Saved Package Form") +fun WooShippingSavedPackageScreen(viewModel: WooShippingLabelPackageCreationViewModel) { + val viewState = viewModel.viewState.observeAsState() + WooShippingSavedPackageScreen( + savedPackages = viewState.value?.savedPackageSelection?.packages.orEmpty(), + isAddPackageEnabled = viewState.value?.savedPackageSelection?.hasSelection ?: false, + onAddPackageClick = viewModel::onAddSavedPackageClick, + onSavedPackageSelected = viewModel::onSavedPackageSelected + + ) +} + +@Composable +fun WooShippingSavedPackageScreen( + modifier: Modifier = Modifier, + savedPackages: List, + isAddPackageEnabled: Boolean, + onAddPackageClick: () -> Unit, + onSavedPackageSelected: (PackageData, Boolean) -> Unit +) { + Column( + modifier = modifier + .fillMaxSize() + ) { + Column( + modifier = modifier + .weight(1f) + .padding(16.dp) + .verticalScroll(rememberScrollState()) + ) { + savedPackages.forEach { packageData -> + WooSavedPackageListItem( + modifier, + packageData, + onSavedPackageSelected + ) + } + } + Column { + Divider() + Button( + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp), + enabled = isAddPackageEnabled, + onClick = onAddPackageClick + ) { + Text(stringResource(id = R.string.woo_shipping_labels_package_creation_add_package)) + } + } + } +} + +@Preview +@Composable +fun WooShippingSavedPackageScreenPreview() { + WooThemeWithBackground { + WooShippingSavedPackageScreen( + savedPackages = listOf( + PackageData( + type = PackageType.ENVELOPE, + name = "Small Flat Rate Box", + description = "USPS Priority Mail Flat Rate Boxes", + length = "10", + width = "10", + height = "10", + isSelected = true + ), + PackageData( + type = PackageType.BOX, + name = "Small Flat Rate Box", + description = "Custom package", + length = "20", + width = "20", + height = "20", + isSelected = false + ), + PackageData( + type = PackageType.BOX, + name = "Small Flat Rate Box", + description = "DHL Express", + length = "30", + width = "30", + height = "30", + isSelected = false + ) + ), + isAddPackageEnabled = true, + onAddPackageClick = {}, + onSavedPackageSelected = { _, _ -> } + ) + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/purchased/WooShippingLabelPurchasedFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/purchased/WooShippingLabelPurchasedFragment.kt new file mode 100644 index 00000000000..44ab07fdf11 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/purchased/WooShippingLabelPurchasedFragment.kt @@ -0,0 +1,47 @@ +package com.woocommerce.android.ui.orders.wooshippinglabels.purchased + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Surface +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed +import androidx.compose.ui.unit.dp +import com.woocommerce.android.R +import com.woocommerce.android.ui.base.BaseFragment +import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class WooShippingLabelPurchasedFragment : BaseFragment() { + + override fun getFragmentTitle(): String = getString(R.string.shipping_label_print_screen_title) + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed) + setContent { + WooThemeWithBackground { + Surface { + val selectedLabelPaperSizeOption = remember { mutableStateOf(WooShippingLabelPaperSize.LEGAL) } + WooShippingLabelPurchasedScreen( + selectedLabelPaperSizeOption = selectedLabelPaperSizeOption.value, + onLabelPaperSizeOptionSelected = { selectedLabelPaperSizeOption.value = it }, + onPrintShippingLabelClicked = { }, + modifier = Modifier.padding(16.dp), + onTrackShipmentClicked = { }, + onSchedulePickUpClicked = { }, + onRefundClicked = { }, + onLearnMoreClicked = { } + ) + } + } + } + } + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/purchased/WooShippingLabelPurchasedScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/purchased/WooShippingLabelPurchasedScreen.kt new file mode 100644 index 00000000000..1d300c0c69e --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/purchased/WooShippingLabelPurchasedScreen.kt @@ -0,0 +1,335 @@ +package com.woocommerce.android.ui.orders.wooshippinglabels.purchased + +import androidx.annotation.StringRes +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.ButtonDefaults.buttonColors +import androidx.compose.material.Colors +import androidx.compose.material.Divider +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.OpenInNew +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.outlined.Info +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Devices +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.woocommerce.android.R +import com.woocommerce.android.ui.compose.component.WCColoredButton +import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground +import com.woocommerce.android.ui.orders.wooshippinglabels.HazmatCard +import com.woocommerce.android.ui.orders.wooshippinglabels.RoundedCornerBoxWithBorder +import com.woocommerce.android.ui.orders.wooshippinglabels.ShippableItems +import com.woocommerce.android.ui.orders.wooshippinglabels.ShippingProductsCard +import com.woocommerce.android.ui.orders.wooshippinglabels.generateItems + +@Suppress("MagicNumber") +private val darkGreen = Color(0xFF005C12) + +@Suppress("MagicNumber") +private val lightGreen = Color(0xFFEDFAEF) + +val Colors.successColor: Color get() = if (isLight) darkGreen else lightGreen + +val Colors.successSurface: Color get() = if (isLight) lightGreen else darkGreen + +@Composable +internal fun WooShippingLabelPurchasedScreen( + selectedLabelPaperSizeOption: WooShippingLabelPaperSize, + onLabelPaperSizeOptionSelected: (WooShippingLabelPaperSize) -> Unit, + onPrintShippingLabelClicked: () -> Unit, + onTrackShipmentClicked: () -> Unit, + onSchedulePickUpClicked: () -> Unit, + onRefundClicked: () -> Unit, + onLearnMoreClicked: () -> Unit, + modifier: Modifier = Modifier, +) { + Column(modifier.verticalScroll(rememberScrollState())) { + Text( + text = stringResource(id = R.string.shipping_label_purchased_title), + style = MaterialTheme.typography.subtitle1, + fontWeight = FontWeight.Bold, + ) + Text( + text = stringResource(id = R.string.shipping_label_purchased_message), + modifier = Modifier.padding(top = 8.dp), + style = MaterialTheme.typography.subtitle1, + ) + Spacer(modifier = Modifier.padding(top = 16.dp)) + PrintShippingLabelCard( + selectedLabelPaperSizeOption = selectedLabelPaperSizeOption, + onLabelPaperSizeOptionSelected = onLabelPaperSizeOptionSelected, + onPrintShippingLabelClicked = onPrintShippingLabelClicked, + onTrackShipmentClicked = onTrackShipmentClicked, + onSchedulePickUpClicked = onSchedulePickUpClicked, + onRefundClicked = onRefundClicked, + onLearnMoreClicked = onLearnMoreClicked, + ) + Text( + text = stringResource(id = R.string.shipping_label_purchased_note), + style = MaterialTheme.typography.caption, + color = colorResource(id = R.color.color_on_surface_medium), + modifier = Modifier.padding(top = 8.dp), + ) + + val isExpanded = remember { mutableStateOf(false) } + ShippingProductsCard( + shippableItems = ShippableItems( + shippableItems = generateItems(6), + totalWeight = "8.5kg", + totalPrice = "$92.78" + ), + isExpanded = isExpanded.value, + onExpand = { isExpanded.value = it }, + iconColor = MaterialTheme.colors.onSurface, + modifier = Modifier.padding(top = 24.dp) + ) + Spacer(modifier = Modifier.padding(top = 16.dp)) + HazmatCard( + modifier = Modifier + .fillMaxWidth() + .background( + color = MaterialTheme.colors.background, + shape = RoundedCornerShape(dimensionResource(R.dimen.corner_radius_large)) + ) + .clip(RoundedCornerShape(dimensionResource(R.dimen.corner_radius_large))), + ) + } +} + +@Preview(showSystemUi = true, device = Devices.PIXEL_4) +@Composable +internal fun WooShippingLabelPurchasedScreenPreview() { + WooThemeWithBackground { + Surface { + val selectedLabelPaperSizeOption = remember { mutableStateOf(WooShippingLabelPaperSize.LEGAL) } + WooShippingLabelPurchasedScreen( + selectedLabelPaperSizeOption = selectedLabelPaperSizeOption.value, + onLabelPaperSizeOptionSelected = { selectedLabelPaperSizeOption.value = it }, + onPrintShippingLabelClicked = {}, + modifier = Modifier.padding(16.dp), + onTrackShipmentClicked = {}, + onSchedulePickUpClicked = {}, + onRefundClicked = {}, + onLearnMoreClicked = {} + ) + } + } +} + +@Composable +private fun PrintShippingLabelCard( + selectedLabelPaperSizeOption: WooShippingLabelPaperSize, + onLabelPaperSizeOptionSelected: (WooShippingLabelPaperSize) -> Unit, + onPrintShippingLabelClicked: () -> Unit, + onTrackShipmentClicked: () -> Unit, + onSchedulePickUpClicked: () -> Unit, + onRefundClicked: () -> Unit, + onLearnMoreClicked: () -> Unit, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .background( + color = MaterialTheme.colors.successSurface, + shape = RoundedCornerShape(dimensionResource(R.dimen.corner_radius_large)) + ) + .padding(16.dp) + ) { + RoundedCornerBoxWithBorder(backgroundColor = MaterialTheme.colors.successSurface) { + LabelPaperSizeDropdownMenu( + selectedLabelPaperSizeOption = selectedLabelPaperSizeOption, + onLabelPaperSizeOptionSelected = onLabelPaperSizeOptionSelected, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 12.dp) + ) + } + + WCColoredButton( + text = stringResource(id = R.string.shipping_label_print_button), + onClick = { onPrintShippingLabelClicked() }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 12.dp, bottom = 4.dp), + colors = buttonColors( + backgroundColor = MaterialTheme.colors.successColor, + contentColor = MaterialTheme.colors.surface + ) + ) + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .clickable { onLearnMoreClicked() } + .padding(vertical = 8.dp) + ) { + Icon( + imageVector = Icons.Outlined.Info, + contentDescription = null, + modifier = Modifier + .padding(end = 8.dp) + .size(16.dp), + tint = MaterialTheme.colors.successColor + ) + Text( + text = stringResource(id = R.string.shipping_label_purchased_learn_how_to_print), + style = MaterialTheme.typography.caption, + color = MaterialTheme.colors.successColor + ) + } + Divider(modifier = Modifier.padding(vertical = 8.dp)) + ShippingLabelLink( + text = stringResource(id = R.string.shipping_label_purchased_track_shipment), + onClick = { + onTrackShipmentClicked() + }, + showIcon = true, + modifier = Modifier.padding(vertical = 8.dp) + ) + ShippingLabelLink( + text = stringResource(id = R.string.shipping_label_purchased_schedule_pick_up), + onClick = { + onSchedulePickUpClicked() + }, + showIcon = true, + modifier = Modifier.padding(vertical = 8.dp) + ) + ShippingLabelLink( + text = stringResource(id = R.string.shipping_label_purchased_request_refund), + onClick = { + onRefundClicked() + }, + showIcon = false, + modifier = Modifier.padding(vertical = 8.dp) + ) + } +} + +@Composable +private fun LabelPaperSizeDropdownMenu( + selectedLabelPaperSizeOption: WooShippingLabelPaperSize, + onLabelPaperSizeOptionSelected: (WooShippingLabelPaperSize) -> Unit, + modifier: Modifier = Modifier, +) { + var expanded by remember { mutableStateOf(false) } + val options = WooShippingLabelPaperSize.entries + + Box { + Row( + modifier = Modifier + .clickable { expanded = true } + .then(modifier), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Text( + text = stringResource(selectedLabelPaperSizeOption.stringResource), + style = MaterialTheme.typography.subtitle1, + modifier = Modifier.weight(1f) + ) + Icon( + imageVector = Icons.Filled.ArrowDropDown, + contentDescription = stringResource( + R.string.sorted_by, + stringResource(selectedLabelPaperSizeOption.stringResource) + ), + tint = MaterialTheme.colors.successColor + + ) + } + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier.align(alignment = Alignment.CenterEnd) + ) { + options.forEach { option -> + DropdownMenuItem(onClick = { + onLabelPaperSizeOptionSelected(option) + expanded = false + }) { + Text( + text = stringResource(option.stringResource), + style = MaterialTheme.typography.subtitle1 + ) + } + } + } + } +} + +@Composable +private fun ShippingLabelLink( + text: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + showIcon: Boolean = false +) { + Row( + modifier = Modifier + .clickable { onClick() } + .then(modifier), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = text, + style = MaterialTheme.typography.subtitle1, + color = MaterialTheme.colors.successColor, + fontWeight = FontWeight.Bold + ) + if (showIcon) { + Icon( + imageVector = Icons.AutoMirrored.Outlined.OpenInNew, + contentDescription = null, + tint = MaterialTheme.colors.successColor, + modifier = Modifier.padding(start = 8.dp) + ) + } + } +} + +@Preview +@Composable +private fun ShippingLabelLinkPreview() { + WooThemeWithBackground { + ShippingLabelLink( + text = "Shipping Label", + onClick = {}, + showIcon = true + ) + } +} + +enum class WooShippingLabelPaperSize(@StringRes val stringResource: Int) { + LEGAL(R.string.shipping_label_paper_size_legal), + LETTER(R.string.shipping_label_paper_size_letter), + LABEL(R.string.shipping_label_paper_size_label) +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingErrorCtaClickHandler.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingErrorCtaClickHandler.kt index 1a248b3a2a6..e68afa4ced6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingErrorCtaClickHandler.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingErrorCtaClickHandler.kt @@ -86,20 +86,14 @@ class CardReaderOnboardingErrorCtaClickHandler @Inject constructor( ) private fun buildReactionToOpenWcPaySetup(): Reaction { - val siteModel = selectedSite.get() val url = selectedSite.get().adminUrlOrDefault.slashJoin(PAYMENTS_TAP_URL) - return if (siteModel.isWPCom || siteModel.isWPComAtomic) { - Reaction.OpenWpComWebView(url) - } else { - Reaction.OpenGenericWebView(url) - } + return Reaction.OpenBrowser(url) } sealed class Reaction { - object Refresh : Reaction() + data object Refresh : Reaction() data class ShowErrorAndRefresh(val message: String) : Reaction() - data class OpenWpComWebView(val url: String) : Reaction() - data class OpenGenericWebView(val url: String) : Reaction() + data class OpenBrowser(val url: String) : Reaction() } private val Reaction.errorMessage diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingEvent.kt index 652b1f99b30..8d6e5f16e4f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingEvent.kt @@ -5,8 +5,7 @@ import com.woocommerce.android.viewmodel.MultiLiveEvent sealed class CardReaderOnboardingEvent : MultiLiveEvent.Event() { object NavigateToSupport : MultiLiveEvent.Event() - data class NavigateToUrlInWPComWebView(val url: String) : MultiLiveEvent.Event() - data class NavigateToUrlInGenericWebView(val url: String) : MultiLiveEvent.Event() + data class NavigateToUrlInBrowser(val url: String) : MultiLiveEvent.Event() data class ContinueToHub(val cardReaderFlowParam: CardReaderFlowParam) : MultiLiveEvent.Event() data class ContinueToConnection( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingFragment.kt index a4d04a9955c..552422e9772 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingFragment.kt @@ -12,7 +12,6 @@ import androidx.core.view.get import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import com.google.android.material.button.MaterialButton -import com.woocommerce.android.NavGraphPaymentFlowDirections import com.woocommerce.android.R import com.woocommerce.android.databinding.FragmentCardReaderOnboardingBinding import com.woocommerce.android.databinding.FragmentCardReaderOnboardingCodDisabledBinding @@ -73,12 +72,7 @@ class CardReaderOnboardingFragment : BaseFragment(R.layout.fragment_card_reader_ is CardReaderOnboardingEvent.NavigateToSupport -> { requireActivity().startHelpActivity(HelpOrigin.CARD_READER_ONBOARDING) } - is CardReaderOnboardingEvent.NavigateToUrlInWPComWebView -> { - findNavController().navigate( - NavGraphPaymentFlowDirections.actionGlobalWPComWebViewFragment(urlToLoad = event.url) - ) - } - is CardReaderOnboardingEvent.NavigateToUrlInGenericWebView -> { + is CardReaderOnboardingEvent.NavigateToUrlInBrowser -> { ChromeCustomTabUtils.launchUrl(requireContext(), event.url) } is CardReaderOnboardingEvent.ContinueToHub -> { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingViewModel.kt index 6c208ef1e21..257eedf6409 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -10,8 +10,7 @@ import com.woocommerce.android.model.UiString import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.payments.cardreader.LearnMoreUrlProvider import com.woocommerce.android.ui.payments.cardreader.LearnMoreUrlProvider.LearnMoreUrlType.IN_PERSON_PAYMENTS -import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingEvent.NavigateToUrlInGenericWebView -import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingEvent.NavigateToUrlInWPComWebView +import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingEvent.NavigateToUrlInBrowser import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingParams.Check import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingParams.Failed import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingState.ChoosePaymentGatewayProvider @@ -116,13 +115,9 @@ class CardReaderOnboardingViewModel @Inject constructor( triggerEvent(Event.ShowUiStringSnackbar(UiString.UiStringText(reaction.message))) refreshState() } - is CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenWpComWebView -> { - triggerEvent(NavigateToUrlInWPComWebView(reaction.url)) - viewState.value = prevState!! - } - is CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenGenericWebView -> { - triggerEvent(NavigateToUrlInGenericWebView(reaction.url)) + is CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenBrowser -> { + triggerEvent(NavigateToUrlInBrowser(reaction.url)) viewState.value = prevState!! } } @@ -421,7 +416,7 @@ class CardReaderOnboardingViewModel @Inject constructor( private fun onLearnMoreClicked() { paymentsFlowTracker.trackOnboardingLearnMoreTapped() - triggerEvent(NavigateToUrlInGenericWebView(learnMoreUrlProvider.provideLearnMoreUrlFor(IN_PERSON_PAYMENTS))) + triggerEvent(NavigateToUrlInBrowser(learnMoreUrlProvider.provideLearnMoreUrlFor(IN_PERSON_PAYMENTS))) } private fun onSkipPendingRequirementsClicked() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/prefs/DeveloperOptionsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/prefs/DeveloperOptionsViewModel.kt index 39271407b1c..02b4ba6cc42 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/prefs/DeveloperOptionsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/prefs/DeveloperOptionsViewModel.kt @@ -156,6 +156,10 @@ class DeveloperOptionsViewModel @Inject constructor( return when (updateFrequency) { UpdateOptions.ALWAYS -> CardReaderManager.SimulatorUpdateFrequency.ALWAYS UpdateOptions.NEVER -> CardReaderManager.SimulatorUpdateFrequency.NEVER + UpdateOptions.LOW_BATTERY_ERROR -> CardReaderManager.SimulatorUpdateFrequency.LOW_BATTERY_ERROR + UpdateOptions.LOW_BATTERY_SUCCEED_CONNECT -> { + CardReaderManager.SimulatorUpdateFrequency.LOW_BATTERY_SUCCEED_CONNECT + } UpdateOptions.RANDOM -> CardReaderManager.SimulatorUpdateFrequency.RANDOM } } @@ -212,6 +216,8 @@ class DeveloperOptionsViewModel @Inject constructor( enum class UpdateOptions(@StringRes val title: Int) { ALWAYS(string.always_update_reader), NEVER(string.never_update_reader), + LOW_BATTERY_ERROR(string.low_battery_error_update_reader), + LOW_BATTERY_SUCCEED_CONNECT(string.low_battery_succeed_connect_update_reader), RANDOM(string.randomly_update_reader) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt index c01e06af72b..6f694586c45 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt @@ -60,6 +60,7 @@ class ParentCategoryListFragment : viewModel.fetchParentCategories() } + @Deprecated("Deprecated in Java") @Suppress("DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt index 64ecb836636..1e905fa83d6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt @@ -133,6 +133,7 @@ class ProductCategoriesFragment : }) } + @Deprecated("Deprecated in Java") @Suppress("DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/list/ProductListAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/list/ProductListAdapter.kt index b751601dc43..c5dc6591fb5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/list/ProductListAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/list/ProductListAdapter.kt @@ -15,7 +15,7 @@ import com.woocommerce.android.util.CurrencyFormatter typealias OnProductClickListener = (remoteProductId: Long, sharedView: View?) -> Unit class ProductListAdapter( - private inline val clickListener: OnProductClickListener? = null, + private val clickListener: OnProductClickListener? = null, private val loadMoreListener: OnLoadMoreListener, private val currencyFormatter: CurrencyFormatter, private val isProductHighlighted: (Long) -> Boolean, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeBaseAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeBaseAdapter.kt index 559d5517f8c..e51e70044c7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeBaseAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeBaseAdapter.kt @@ -7,7 +7,7 @@ import com.woocommerce.android.databinding.AttributeItemBinding import com.woocommerce.android.model.ProductAttribute abstract class AttributeBaseAdapter( - private inline val onItemClick: (attributeId: Long, attributeName: String) -> Unit + private val onItemClick: (attributeId: Long, attributeName: String) -> Unit ) : RecyclerView.Adapter() { private var attributeList = listOf() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt index 73a41e2aa61..b8fe7ed95d5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt @@ -81,6 +81,7 @@ class ReviewDetailFragment : return inflater.inflate(R.layout.fragment_review_detail, container, false) } + @Deprecated("Deprecated in Java") @Suppress("DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewModeration.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewModeration.kt index 980d0f52b84..d974e9bfce0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewModeration.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewModeration.kt @@ -4,17 +4,11 @@ import com.woocommerce.android.model.ActionStatus import com.woocommerce.android.model.ActionStatus.PENDING import com.woocommerce.android.model.ProductReview -@Suppress("DataClassPrivateConstructor") -data class ReviewModerationRequest private constructor( +data class ReviewModerationRequest( val review: ProductReview, val newStatus: ProductReviewStatus, - private val timeOfRequest: Long ) : Comparable { - constructor(review: ProductReview, newStatus: ProductReviewStatus) : this( - review, - newStatus, - System.currentTimeMillis() - ) + private val timeOfRequest = System.currentTimeMillis() override fun compareTo(other: ReviewModerationRequest): Int { return timeOfRequest.compareTo(other.timeOfRequest) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/sitepicker/SitePickerViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/sitepicker/SitePickerViewModel.kt index 3abf64135cd..e5469b3f59b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/sitepicker/SitePickerViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/sitepicker/SitePickerViewModel.kt @@ -339,7 +339,7 @@ class SitePickerViewModel @Inject constructor( ) sitePickerViewState = sitePickerViewState.copy( isSkeletonViewVisible = false, - isPrimaryBtnVisible = sites.value!!.any { it is WooSiteUiModel } + isPrimaryBtnVisible = sites.value?.any { it is WooSiteUiModel } ?: false ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeChildToParentCommunication.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeChildToParentCommunication.kt index 105ba84ff87..329edc2e0c1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeChildToParentCommunication.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeChildToParentCommunication.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.woopos.home +import com.woocommerce.android.ui.woopos.home.items.WooPosItemNavigationData import dagger.hilt.android.scopes.ActivityRetainedScoped import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -20,7 +21,7 @@ class WooPosChildrenToParentCommunication @Inject constructor() : sealed class ChildToParentEvent { data class CheckoutClicked(val productIds: List) : ChildToParentEvent() data object BackFromCheckoutToCartClicked : ChildToParentEvent() - data class ItemClickedInProductSelector(val productId: Long) : ChildToParentEvent() + data class ItemClickedInProductSelector(val itemData: WooPosItemNavigationData) : ChildToParentEvent() data object NewTransactionClicked : ChildToParentEvent() data object OrderSuccessfullyPaid : ChildToParentEvent() data object ExitPosClicked : ChildToParentEvent() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeParentToChildCommunication.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeParentToChildCommunication.kt index 3b78b23ba9b..6e6bc248d18 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeParentToChildCommunication.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeParentToChildCommunication.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.woopos.home +import com.woocommerce.android.ui.woopos.home.items.WooPosItemNavigationData import dagger.hilt.android.scopes.ActivityRetainedScoped import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -19,7 +20,7 @@ class WooPosParentToChildrenCommunication @Inject constructor() : sealed class ParentToChildrenEvent { data object BackFromCheckoutToCartClicked : ParentToChildrenEvent() - data class ItemClickedInProductSelector(val productId: Long) : ParentToChildrenEvent() + data class ItemClickedInProductSelector(val itemData: WooPosItemNavigationData) : ParentToChildrenEvent() data class CheckoutClicked(val productIds: List) : ParentToChildrenEvent() data object OrderSuccessfullyPaid : ParentToChildrenEvent() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt index 2e1f6c56054..b7ebdffaac7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt @@ -100,7 +100,7 @@ class WooPosHomeViewModel @Inject constructor( is ChildToParentEvent.ItemClickedInProductSelector -> { sendEventToChildren( - ParentToChildrenEvent.ItemClickedInProductSelector(event.productId) + ParentToChildrenEvent.ItemClickedInProductSelector(event.itemData) ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModel.kt index 1d7fe57ecfe..2367550d75c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModel.kt @@ -118,7 +118,7 @@ class WooPosCartViewModel @Inject constructor( is ParentToChildrenEvent.ItemClickedInProductSelector -> { val itemClicked = async { - val product = getProductById(event.productId)!! + val product = getProductById(event.itemData.id)!! val itemNumber = when (val currentState = _state.value.body) { is WooPosCartState.Body.Empty -> 1 is WooPosCartState.Body.WithItems -> diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItem.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItem.kt index 8e7f7acd417..b42b60d6cac 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItem.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItem.kt @@ -10,4 +10,13 @@ sealed class WooPosItem( val price: String, val imageUrl: String?, ) : WooPosItem(id, name) + + data class VariableProduct( + override val id: Long, + override val name: String, + val price: String, + val imageUrl: String?, + val numOfVariations: Int, + val variationIds: List, + ) : WooPosItem(id, name) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItemsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItemsScreen.kt index b58d9178e01..d0ddabd40f7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItemsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItemsScreen.kt @@ -71,6 +71,7 @@ import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosLazyCo import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosShimmerBox import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding import com.woocommerce.android.ui.woopos.home.items.WooPosItem.SimpleProduct +import com.woocommerce.android.ui.woopos.home.items.WooPosItem.VariableProduct import com.woocommerce.android.ui.woopos.home.items.WooPosItemsUIEvent.EndOfItemsListReached import com.woocommerce.android.ui.woopos.home.items.WooPosItemsUIEvent.ItemClicked import com.woocommerce.android.ui.woopos.home.items.WooPosItemsUIEvent.ProductsLoadingErrorRetryButtonClicked @@ -181,7 +182,9 @@ private fun ItemsToolbar( onToolbarInfoIconClicked: () -> Unit, ) { Row( - modifier = Modifier.fillMaxWidth().height(40.dp), + modifier = Modifier + .fillMaxWidth() + .height(40.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.Top, ) { @@ -267,6 +270,14 @@ private fun ItemsList( onItemClicked = onItemClicked ) } + + is VariableProduct -> { + VariableProductItem( + modifier = Modifier.animateItemPlacement(), + item = product, + onItemClicked = onItemClicked + ) + } } } @@ -347,13 +358,37 @@ private fun ItemsLoadingItem() { private fun ProductItem( modifier: Modifier = Modifier, item: SimpleProduct, - onItemClicked: (item: SimpleProduct) -> Unit + onItemClicked: (item: WooPosItem) -> Unit +) { + val itemContentDescription = stringResource( + id = R.string.woopos_product_item_content_description, + item.name, + item.price + ) + ItemCard(modifier, itemContentDescription, onItemClicked, item) +} + +@Composable +private fun VariableProductItem( + modifier: Modifier = Modifier, + item: VariableProduct, + onItemClicked: (item: WooPosItem) -> Unit ) { val itemContentDescription = stringResource( - id = R.string.woopos_cart_item_content_description, + id = R.string.woopos_variable_product_item_content_description, item.name, item.price ) + ItemCard(modifier, itemContentDescription, onItemClicked, item) +} + +@Composable +private fun ItemCard( + modifier: Modifier, + itemContentDescription: String, + onItemClicked: (item: WooPosItem) -> Unit, + item: WooPosItem +) { WooPosCard( modifier = modifier .semantics { contentDescription = itemContentDescription }, @@ -369,42 +404,80 @@ private fun ProductItem( .fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(item.imageUrl) - .crossfade(true) - .build(), - fallback = ColorPainter(WooPosTheme.colors.loadingSkeleton), - error = ColorPainter(WooPosTheme.colors.loadingSkeleton), - placeholder = ColorPainter(WooPosTheme.colors.loadingSkeleton), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier.size(112.dp) - ) + ProductImage(item) Spacer(modifier = Modifier.width(32.dp)) - Text( - modifier = Modifier.weight(1f), - text = item.name, - style = MaterialTheme.typography.h5, - fontWeight = FontWeight.SemiBold, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - - Spacer(modifier = Modifier.width(32.dp)) - - Text( - text = item.price, - style = MaterialTheme.typography.h5, - ) + ProductInfo(item) + } + } +} - Spacer(modifier = Modifier.width(24.dp)) +@Composable +private fun ProductInfo(item: WooPosItem) { + Column( + modifier = Modifier + .fillMaxHeight() + .padding(vertical = 8.dp), + verticalArrangement = Arrangement.Center + ) { + Text( + text = item.name, + style = MaterialTheme.typography.h5, + fontWeight = FontWeight.SemiBold, + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) + Spacer(modifier = Modifier.height(8.dp)) + when (item) { + is SimpleProduct -> SimpleProductDetails(item = item) + is VariableProduct -> VariableProductDetails(item = item) } } } +@Composable +private fun ProductImage(item: WooPosItem) { + val imageUrl = when (item) { + is SimpleProduct -> item.imageUrl + is VariableProduct -> item.imageUrl + } + + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(imageUrl) + .crossfade(true) + .build(), + fallback = ColorPainter(WooPosTheme.colors.loadingSkeleton), + error = ColorPainter(WooPosTheme.colors.loadingSkeleton), + placeholder = ColorPainter(WooPosTheme.colors.loadingSkeleton), + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier.size(112.dp) + ) +} + +@Composable +private fun SimpleProductDetails(item: SimpleProduct) { + Text( + text = item.price, + style = MaterialTheme.typography.h6, + fontWeight = FontWeight.Normal + ) +} + +@Composable +private fun VariableProductDetails(item: VariableProduct) { + Text( + text = stringResource( + id = R.string.woopos_items_list_variable_product_variations, + item.numOfVariations + ), + style = MaterialTheme.typography.h6, + fontWeight = FontWeight.Normal + ) +} + @Composable fun ProductsEmptyList() { Box( @@ -512,9 +585,17 @@ fun WooPosItemsScreenPreview(modifier: Modifier = Modifier) { price = "2000.00$", imageUrl = null, ), - SimpleProduct( + VariableProduct( 3, name = "Product 3", + price = "2000.00$", + imageUrl = null, + numOfVariations = 20, + variationIds = listOf() + ), + SimpleProduct( + 4, + name = "Product 4", price = "1.0$", imageUrl = null, ), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItemsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItemsViewModel.kt index 9b07395806b..1b68fb31e76 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItemsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/items/WooPosItemsViewModel.kt @@ -4,9 +4,11 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.woocommerce.android.R import com.woocommerce.android.model.Product +import com.woocommerce.android.ui.products.ProductType import com.woocommerce.android.ui.woopos.home.ChildToParentEvent import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender import com.woocommerce.android.ui.woopos.home.items.WooPosItem.SimpleProduct +import com.woocommerce.android.ui.woopos.home.items.WooPosItem.VariableProduct import com.woocommerce.android.ui.woopos.home.items.products.WooPosProductsDataSource import com.woocommerce.android.ui.woopos.util.datastore.WooPosPreferencesRepository import com.woocommerce.android.ui.woopos.util.format.WooPosFormatPrice @@ -97,6 +99,9 @@ class WooPosItemsViewModel @Inject constructor( ) ) } + + is VariableProduct -> { + } } } @@ -171,12 +176,23 @@ class WooPosItemsViewModel @Inject constructor( private suspend fun List.toContentState() = WooPosItemsViewState.Content( items = map { product -> - SimpleProduct( - id = product.remoteId, - name = product.name, - price = priceFormat(product.price), - imageUrl = product.firstImageUrl, - ) + if (product.isVariable()) { + VariableProduct( + id = product.remoteId, + name = product.name, + price = priceFormat(product.price), + imageUrl = product.firstImageUrl, + numOfVariations = product.numVariations, + variationIds = product.variationIds + ) + } else { + SimpleProduct( + id = product.remoteId, + name = product.name, + price = priceFormat(product.price), + imageUrl = product.firstImageUrl, + ) + } }, loadingMore = false, reloadingProductsWithPullToRefresh = false, @@ -229,8 +245,8 @@ class WooPosItemsViewModel @Inject constructor( ) } - private fun onItemClicked(itemData: WooPosItemNavigationData.SimpleProductData) { - sendEventToParent(ChildToParentEvent.ItemClickedInProductSelector(itemData.id)) + private fun onItemClicked(itemData: WooPosItemNavigationData) { + sendEventToParent(ChildToParentEvent.ItemClickedInProductSelector(itemData)) } private fun sendEventToParent(event: ChildToParentEvent) { @@ -240,4 +256,8 @@ class WooPosItemsViewModel @Inject constructor( private suspend fun isBannerHiddenByUser(): Boolean { return preferencesRepository.isSimpleProductsOnlyBannerWasHiddenByUser.first() } + + private fun Product.isVariable() = + productType == ProductType.VARIABLE || + productType == ProductType.VARIATION } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/ItemDecorators.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/ItemDecorators.kt index 72ee2e68d1f..a963cc4ae84 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/ItemDecorators.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/ItemDecorators.kt @@ -23,6 +23,7 @@ class GridItemDecoration( } class HorizontalItemDecoration(private val spacing: Int) : ItemDecoration() { + @Deprecated("Deprecated in Java") override fun getItemOffsets(outRect: Rect, itemPosition: Int, parent: RecyclerView) { outRect.left = spacing outRect.right = spacing diff --git a/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml b/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml index 616f16d53c6..49044c7d8ba 100644 --- a/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml +++ b/WooCommerce/src/main/res/navigation/nav_graph_blaze_campaign_creation.xml @@ -95,6 +95,10 @@ android:name="description" android:defaultValue="" app:argType="string" /> + diff --git a/WooCommerce/src/main/res/navigation/nav_graph_orders.xml b/WooCommerce/src/main/res/navigation/nav_graph_orders.xml index 93e2fcd16c2..8a00df24f18 100644 --- a/WooCommerce/src/main/res/navigation/nav_graph_orders.xml +++ b/WooCommerce/src/main/res/navigation/nav_graph_orders.xml @@ -753,9 +753,22 @@ + + android:label="WooShippingLabelPackageCreationFragment" > + + + + + diff --git a/WooCommerce/src/main/res/values-ar/strings.xml b/WooCommerce/src/main/res/values-ar/strings.xml index 8b7519f15cc..14606184d3b 100644 --- a/WooCommerce/src/main/res/values-ar/strings.xml +++ b/WooCommerce/src/main/res/values-ar/strings.xml @@ -1,11 +1,47 @@ + ظرف + صندوق + إضافة طرد + حفظ ذلك كنموذج طرد جديد + الارتفاع + العرض + المدة + نوع الطرد + تم الحفظ + شركة نقل + مخصص + طلب استرداد الأموال + جدولة الاستلام + تعقب الشحنة + التعرف على كيفية الطباعة من جهازك المحمول + ملاحظة: يُعد إعادة استخدام ملصق طباعة انتهاكًا لشروط الخدمة وقد يؤدي إلى توجيه اتهامات جنائية. + من هنا، يمكنك طباعة ملصق الشحن مجددًا أو تغيير حجم ورق الملصق. + ملصق الشحن لديك جاهز للطباعة + عذرًا، لا يمكنك سوى تحرير هذا الطلب على الويب، لأنه يستخدم ⁦%1$s⁩، وعملة موقعك هي ⁦%2$s⁩ + خدمة الشحن + الأسرع + الأرخص + ملصق الشراء + ملصق الشراء · ⁦%1$s⁩ + وضع علامة على هذا الطلب على أنه مكتمل وإخطار العميل + تكلفة الشحنة + تفاصيل الطلب + تفاصيل الشحنة + أدخل أبعاد الطرد الخاص بك أو استلم خيار الطرد الخاص بشركة النقل للاطلاع على أسعار الشحن المتاحة. + تحديد طرد للحصول على أسعار الشحن + تحديد طرد + هل تشحن بضائع خطيرة أو مواد خطرة؟ + طي/توسيع بطاقة المنتجات + %1$s  ·  %2$s + تم الفرز حسب 1%s + لا حفظ التحديد الخاص بي للحملات المستقبلية <b>مناسب لـ:</b> %s تحديد هدف %s @@ -554,7 +590,7 @@ Language: ar تحصيل المدفوعات ينبغي أن يكون الكود بتنسيق XXXX-XXXX-XXXX-XXXX إدخال الكود - القسيمة + القسائم فشل تحميل القوالب. اكتمل التكوين تم التراجع عن تحديث الكمية @@ -3637,6 +3673,7 @@ Language: ar الضرائب السداد الشحن + الإجمالي -%1$s%2$s %1$s%2$s الطلبات diff --git a/WooCommerce/src/main/res/values-de/strings.xml b/WooCommerce/src/main/res/values-de/strings.xml index 5665049fcc4..4abe5086eab 100644 --- a/WooCommerce/src/main/res/values-de/strings.xml +++ b/WooCommerce/src/main/res/values-de/strings.xml @@ -1,11 +1,47 @@ + Umschlag + Karton + Paket hinzufügen + Als neues Paket-Template speichern + Höhe + Breite + Länge + Paketart + Gespeichert + Versanddienstleister + Individuell + Rückerstattung anfordern + Abholung planen + Sendung verfolgen + So druckst du von deinem Mobilgerät aus + Hinweis: Das Wiederverwenden eines ausgedruckten Etiketts ist ein Verstoß gegen unsere Geschäftsbedingungen und kann strafrechtliche Konsequenzen nach sich ziehen. + Hier kannst du das Versandetikett erneut drucken oder das Papierformat des Etiketts ändern. + Dein Versandetikett kann jetzt gedruckt werden + Leider kannst du diese Bestellung nur im Web bearbeiten, da %1$s verwendet wird und die Währung deiner Website %2$s ist + Versanddienst + Etikett kaufen + Etikett kaufen · %1$s + Schnellste + Günstigste + Versandkosten + Bestelldetails + Versanddetails + Gib die Abmessungen deines Pakets ein oder wähle eine Paketoption, um die verfügbaren Versandtarife zu sehen. + Paket auswählen, damit Versandtarife angezeigt werden + Paket auswählen + Versendest du Gefahrgut oder gefährliche Stoffe? + Diese Bestellung als abgeschlossen markieren und den Kunden benachrichtigen + Artikelkarte einklappen/aufklappen + %1$s  ·  %2$s + Nein. + Sortiert nach %s Meine Auswahl für zukünftige Kampagnen speichern <b>Gut für:</b> %s Ziel %s auswählen @@ -500,6 +536,7 @@ Language: de Bild ändern Übernehmen %1$s Tage + Aufrufe geben die Häufigkeit an, mit der deine Werbung potenziellen Kunden angezeigt wird.\n\n\n Auch wenn aufgrund von schwankendem Internet-Traffic und Nutzerverhalten keine genauen Zahlen garantiert werden können, versuchen wir, die tatsächlichen Aufrufe deiner Werbeanzeige so genau wie möglich mit deiner Zielzahl abzugleichen.\n\n\n Denke daran, dass es bei Aufrufen um die Sichtbarkeit geht und nicht um vom Betrachter ausgeführte Aktionen. Fertig Aufrufe Update @@ -509,7 +546,6 @@ Language: de Dein Budget festlegen Alle %1$s Tage seit %2$s - Aufrufe geben die Häufigkeit an, mit der deine Werbung potenziellen Kunden angezeigt wird.\n\n\n Auch wenn aufgrund von schwankendem Internet-Traffic und Nutzerverhalten keine genauen Zahlen garantiert werden können, versuchen wir, die tatsächlichen Aufrufe deiner Werbeanzeige so genau wie möglich mit deiner Zielzahl abzugleichen.\n\n\n Denke daran, dass es bei Aufrufen um die Sichtbarkeit geht und nicht um vom Betrachter ausgeführte Aktionen. %1$s täglich Startdatum Nicht erneut anzeigen @@ -554,7 +590,7 @@ Language: de Zahlung empfangen Der Code muss folgendes Format haben: XXXX-XXXX-XXXX-XXXX Code eingeben - Gutschein + Gutscheine Themes konnten nicht geladen werden. Konfiguration abgeschlossen Mengenaktualisierung rückgängig gemacht @@ -3631,6 +3667,7 @@ Language: de Steuern Zahlung Versand + Insgesamt -%1$s%2$s %1$s%2$s Bestellungen diff --git a/WooCommerce/src/main/res/values-es/strings.xml b/WooCommerce/src/main/res/values-es/strings.xml index c43d8b4636e..125f533d43c 100644 --- a/WooCommerce/src/main/res/values-es/strings.xml +++ b/WooCommerce/src/main/res/values-es/strings.xml @@ -1,11 +1,47 @@ + Envoltorio + Caja + Añadir paquete + Guardar como nueva plantilla de paquete + Altura + Ancho + Longitud + Tipo de paquete + Guardado + Empresa de transportes + Personalizado + Solicitar reembolso + Programar la recogida + Hacer un seguimiento del envío + Aprende a imprimir desde tu dispositivo móvil + Nota: La reutilización de una etiqueta impresa es una violación de nuestras condiciones del servicio y podría resultar en cargos criminales. + Desde aquí puedes volver a imprimir la etiqueta de envío o cambiar el tamaño de papel de la etiqueta. + Tu etiqueta de envío está lista para imprimirse + Lo sentimos, solo puedes editar este pedido en la web, ya que utiliza %1$s, y la moneda de tu sitio es %2$s + Servicio de envío + Más rápida + Más barata + Etiqueta de compra + Etiqueta de compra %1$s + Marcar este pedido como completado y avisar al cliente + Coste de envío + Detalles del pedido + Detalles del envío + Introduce las dimensiones de tu paquete o elige una opción de paquete de empresa de transporte para ver las tarifas de envío disponibles. + Elige un paquete para obtener las tarifas de envío + Elige un paquete + ¿Vas a enviar mercancías peligrosas? + Contraer/ampliar tarjeta de elementos + %1$s  ·  %2$s + Ordenado por 1%s + No Guardar mi selección para futuras campañas <b>Ideal para:</b> %s Elegir objetivo %s @@ -554,7 +590,7 @@ Language: es Recibir pago El código debe tener el formato XXXX-XXXX-XXXX-XXXX Introduce el código - Cupón + Cupones No se han podido cargar los temas. Configuración completada Actualizar cantidad deshecha @@ -3637,6 +3673,7 @@ Language: es Impuestos Pago Envío + Total -%1$s%2$s %1$s%2$s Pedidos diff --git a/WooCommerce/src/main/res/values-fr/strings.xml b/WooCommerce/src/main/res/values-fr/strings.xml index ee8d9a6e604..f01f9efa169 100644 --- a/WooCommerce/src/main/res/values-fr/strings.xml +++ b/WooCommerce/src/main/res/values-fr/strings.xml @@ -1,11 +1,47 @@ + Enveloppe + Boîte + Ajouter un colis + L’enregistrer comme nouveau modèle de colis + Hauteur + Largeur + Longueur + Type de colis + Enregistré + Transporteur + Personnalisé + Demander un remboursement + Planifier le retrait + Suivre l’expédition + Découvrir comment imprimer à partir de votre appareil mobile + Remarque : la réutilisation d’une étiquette imprimée constitue une violation de nos conditions d’utilisation susceptible d’entraîner des poursuites judiciaires. + Vous pouvez réimprimer l’étiquette d’expédition ou modifier la dimension de l’étiquette ici. + Votre étiquette d’expédition est prête pour l’impression + Toutes nos excuses, vous pouvez modifier cette commande sur le Web uniquement car elle est en %1$s et votre site est en %2$s + Service d’expédition + Le plus rapide + Le moins cher + Acheter une étiquette + Acheter une étiquette · %1$s + Marquer cette commande comme terminée et informer le client + Frais d’expédition + Détails de la commande + Détails de l’expédition + Saisissez les dimensions de votre colis ou sélectionnez une option de colis du transporteur pour voir les tarifs d’expédition disponibles. + Sélectionner un colis pour obtenir les tarifs d’expédition + Sélectionner un colis + Expédiez-vous des marchandises ou matières dangereuses ? + Réduire / développer l’affichage de la fiche d’articles + %1$s  ·  %2$s + Trié par 1%s + Non Enregistrer ma sélection pour de futures campagnes <b>Idéal pour :</b> %s Sélectionner un objectif %s @@ -554,7 +590,7 @@ Language: fr Percevoir le paiement Le code doit respecter le format XXXX-XXXX-XXXX-XXXX Saisir le code - Code promo + Codes promo Chargement des thèmes impossible. Configuration terminée Mettre à jour la quantité annulé @@ -3637,6 +3673,7 @@ Language: fr Taxes Paiement Expédition + Total -%1$s%2$s %1$s%2$s Commandes diff --git a/WooCommerce/src/main/res/values-he/strings.xml b/WooCommerce/src/main/res/values-he/strings.xml index 4a34cbd5c40..957d48beb9c 100644 --- a/WooCommerce/src/main/res/values-he/strings.xml +++ b/WooCommerce/src/main/res/values-he/strings.xml @@ -1,11 +1,47 @@ + מעטפה + קופסה + להוסיף חבילה + יש לשמור את התבנית הזו כתבנית חבילה חדשה + גובה + רוחב + אורך + סוג חבילה + נשמר + חברת שילוח + התאמה אישית + לבקש החזר כספי + לתזמן איסוף + מעקב אחר משלוח + ללמוד כיצד להדפיס באמצעות המכשיר הנייד שלך + הערה: שימוש חוזר בתווית שהודפסה הוא הפרה של תנאי השימוש שלנו ועשוי להוביל לכתב אישום. + מכאן אפשר להדפיס את תווית המשלוח שוב או לשנות את גודל הנייר של התווית. + תווית המשלוח שלך מוכנה להדפסה + מצטערים, אפשר לערוך את ההזמנה הזאת רק באתר האינטרנט, מאחר שהיא משתמשת במטבע ⁦%1$s⁩ והאתר שלך מוגדר למטבע ⁦%2$s⁩ + שירות משלוחים + המהיר ביותר + הזול ביותר + לרכוש תווית + לרכוש תווית ⁦%1$s⁩ + לסמן את ההזמנה כ\'הושלמה\' ולהודיע ללקוח + עלות משלוח + פרטי הזמנה + פרטי המשלוח + יש להזין את ממדי החבילה או לבחור אפשרות של חבילת ספק כדי להציג את תעריפי המשלוח. + יש לבחור חבילה כדי להציג את תעריפי המשלוח + יש לבחור חבילה + המשלוח שלך כולל סחורות מסוכנות או חומרים מסוכנים? + לכווץ/להרחיב את כרטיס הפריטים + %1$s  ·  %2$s + ממוין לפי 1%s + לא לשמור את הבחירה שלי עבור קמפיינים עתידיים <b>מומלץ עבור:</b> %s לבחור מטרה %s @@ -554,7 +590,7 @@ Language: he_IL לגבות תשלום הקוד אמור להיות בפורמט XXXX-XXXX-XXXX-XXXX יש להזין קוד - קופון + קופונים העלאת ערכות העיצוב נכשלה. הושלמו הגדרות התצורה עדכון הכמות בוטל @@ -3637,6 +3673,7 @@ Language: he_IL מיסים תשלום משלוח + סה\"כ -%1$s%2$s %1$s%2$s הזמנות diff --git a/WooCommerce/src/main/res/values-id/strings.xml b/WooCommerce/src/main/res/values-id/strings.xml index 3c9f8906bf1..dfa22854789 100644 --- a/WooCommerce/src/main/res/values-id/strings.xml +++ b/WooCommerce/src/main/res/values-id/strings.xml @@ -1,11 +1,47 @@ + Amplop + Kotak + Tambah Paket + Simpan ini sebagai templat paket baru + Tinggi + Lebar + Panjang + Tipe paket + Disimpan + Operator + Kustom + Minta pengembalian dana + Jadwalkan pengambilan + Lacak pengiriman + Pelajari cara mencetak dari perangkat seluler Anda + Catatan: Penggunaan kembali label yang dicetak adalah tindakan yang melanggar ketentuan layanan kami dan dapat mengakibatkan tuntutan pidana. + Dari sini, Anda dapat mencetak label pengiriman lagi atau mengubah ukuran kertas label. + Label pengiriman siap dicetak + Maaf, Anda hanya bisa mengedit pesanan ini di web, karena pesanan menggunakan %1$s, dan mata uang situs Anda adalah %2$s + Layanan pengiriman + Tercepat + Termurah + Beli Label + Beli Label · %1$s + Tandai pesanan ini selesai dan kirim pemberitahuan ke pelanggan + Biaya pengiriman + Rincian pesanan + Rincian pengiriman + Masukkan dimensi paket Anda atau pilih opsi paket operator untuk melihat tarif pengiriman yang tersedia. + Pilih paket untuk melihat tarif pengiriman + Pilih Paket + Apakah Anda mengirim barang berisiko atau bahan berbahaya? + %1$s  ·  %2$s + Ciutkan/perluas kartu item + Tidak + Diurutkan berdasarkan 1%s Simpan pilihan saya untuk kampanye mendatang. <b>Cocok untuk:</b> %s Pilih tujuan %s @@ -3631,6 +3667,7 @@ Language: id Pajak Pembayaran Pengiriman + Total -%1$s%2$s %1$s%2$s Pesanan diff --git a/WooCommerce/src/main/res/values-it/strings.xml b/WooCommerce/src/main/res/values-it/strings.xml index ecd7a15d55d..b26a7265e8a 100644 --- a/WooCommerce/src/main/res/values-it/strings.xml +++ b/WooCommerce/src/main/res/values-it/strings.xml @@ -1,11 +1,47 @@ + Busta + Confezione + Aggiungi pacchetto + Altezza + Larghezza + Lunghezza + Tipo di pacchetto + Salvato + Corriere + Personalizza + Richiedi rimborso + Pianifica ritiro + Traccia spedizione + Scopri come stampare dal tuo dispositivo mobile + Salvalo come nuovo template di pacchetto + Nota: il riutilizzo di un\'etichetta stampata viola i nostri termini di servizio e può comportare una denuncia penale. + Da qui puoi stampare di nuovo l\'etichetta di spedizione o cambiare il formato carta per l\'etichetta. + La tua etichetta di spedizione è pronta per la stampa + Spiacenti, puoi modificare questo ordine solo sul web, in quanto utilizza %1$s, mentre la valuta del tuo sito è %2$s + Servizio di spedizione + Più veloce + Più economico + Acquista etichetta + Acquista etichetta · %1$s + Contrassegna questo ordine come completato e invia una notifica al cliente + Costo spedizione + Dettagli ordine + Dettagli spedizione + Immetti le dimensioni del tuo pacchetto o scegli un\'opzione di pacchetto del corriere per visualizzare le tariffe di spedizione disponibili. + Seleziona un pacchetto per ottenere le tariffe di spedizione + Seleziona un pacchetto + Stai spedendo beni pericolosi o materiale nocivo? + Comprimi/espandi la scheda degli articoli + %1$s  ·  %2$s + No + Ordinamento per 1%s Salva la mia selezione per le campagne future <b>Ottimo per:</b> %s Seleziona obiettivo %s @@ -553,8 +589,8 @@ Language: it Ricevi pagamenti Il codice dovrebbe essere nel formato XXXX-XXXX-XXXX-XXXX Inserisci codice - Codice promozionale Il nostro strumento è stato progettato per consentire ai venditori di impostare annunci semplici e veloci per incrementare al massimo il traffico. + Codici promozionali Impossibile caricare i temi. Configurazione completata Aggiornamento quantità annullato @@ -3630,6 +3666,7 @@ Language: it Tasse Pagamento Spedizione + Totale -%1$s%2$s %1$s%2$s Ordini diff --git a/WooCommerce/src/main/res/values-ja/strings.xml b/WooCommerce/src/main/res/values-ja/strings.xml index 8ee0a09a55f..67c331e9fcf 100644 --- a/WooCommerce/src/main/res/values-ja/strings.xml +++ b/WooCommerce/src/main/res/values-ja/strings.xml @@ -1,11 +1,47 @@ + 封筒 + ボックス + パッケージを追加 + これを新しいパッケージテンプレートとして保存 + 高さ + + 長さ + パッケージの種類 + 保存済み + 運送業者 + カスタム + 返金をリクエスト + 集荷日を設定 + 配送状況を追跡 + モバイルデバイスを使って印刷する方法を確認 + 注意: 印刷されたラベルを再利用すると、弊社の利用規約違反となり、刑事責任を問われる可能性があります。 + こちらから再度配送ラベルを印刷するか、ラベルの用紙サイズを変更することができます。 + 配送ラベルを印刷する準備ができました + この注文は %1$s を使用しており、サイトの通貨は %2$s であるため、編集はウェブ上でしか行えません + 配送サービス + 最速 + 最安値 + ラベルを購入 + ラベルを購入 · %1$s + この注文に完了のマークを付けてお客様に通知 + 配送料 + 注文詳細 + 配送状況の詳細 + 荷物の寸法を入力するか、配送業者の荷物オプションを選択して、利用可能な配送料金を確認してください。 + 荷物を選択して配送料を取得 + 荷物を選択 + 危険物または有害物質を発送しようとしていますか ? + アイテムカードを折りたたむ / 展開する + %1$s  ·  %2$s + 1%sで並べ替え + いいえ 今後のキャンペーンのために選択を保存 <b>効果:</b> %s 目的 %s を選択 @@ -3637,6 +3673,7 @@ Language: ja_JP 決済 配送 + 合計 -%1$s%2$s %1$s%2$s 注文 diff --git a/WooCommerce/src/main/res/values-ko/strings.xml b/WooCommerce/src/main/res/values-ko/strings.xml index ba9fd79b2f8..5d129e3b9a3 100644 --- a/WooCommerce/src/main/res/values-ko/strings.xml +++ b/WooCommerce/src/main/res/values-ko/strings.xml @@ -1,11 +1,47 @@ + 봉투 + 상자 + 패키지 추가 + 이 템플릿을 새 패키지 템플릿으로 저장 + 높이 + + 길이 + 패키지 유형 + 저장됨 + 배송업체 + 사용자 정의 + 환불 요청 + 픽업 예약 + 배송 추적 + 모바일 장치에서 인쇄하는 방법 알아보기 + 참고: 인쇄된 레이블을 재사용하는 행위는 서비스 약관 위반이며 형사 고발될 수 있습니다. + 여기에서 배송 레이블을 다시 인쇄하거나 레이블의 용지 크기를 변경할 수 있습니다. + 배송 레이블을 인쇄할 준비가 되었습니다. + 죄송합니다. 이 주문에서는 %1$s을(를) 사용하고 사이트의 통화는 %2$s이므로 웹에서만 이 주문을 편집할 수 있습니다. + 배송 서비스 + 가장 빠름 + 가장 저렴 + 레이블 구매 + 레이블 구매 · %1$s + 이 주문을 완료로 표시하고 고객에게 알립니다. + 배송비 + 주문 상세 정보 + 배송 상세 정보 + 패키지의 크기를 입력하거나 배송업체 패키지 옵션을 선택하여 적용 가능한 배송비를 확인하세요. + 배송비를 가져올 패키지 선택 + 패키지 선택 + 위험물 또는 유해물질을 배송하시나요? + 아이템 카드 축소/확장 + %1$s  ·  %2$s + 1%s 기준으로 정렬됨 + 아니요 향후 캠페인을 위해 내 선택 사항 저장 <b>다음과 같은 상황에 적합:</b> %s 목표 %s 선택 @@ -3637,6 +3673,7 @@ Language: ko_KR 세금 결제 배송 + 총계 -%1$s%2$s %1$s%2$s 주문 diff --git a/WooCommerce/src/main/res/values-nl/strings.xml b/WooCommerce/src/main/res/values-nl/strings.xml index 058bcbd6bf3..3b7c4fef79d 100644 --- a/WooCommerce/src/main/res/values-nl/strings.xml +++ b/WooCommerce/src/main/res/values-nl/strings.xml @@ -1,11 +1,47 @@ + Envelop + Doos + Pakket toevoegen + Opslaan als nieuwe pakketsjabloon + Hoogte + Breedte + Lengte + Pakkettype + Opgeslagen + Bezorgservice + Aangepast + Terugbetaling aanvragen + Een afhaaltijd plannen + Verzending volgen + Leer hoe je kan printen vanaf je mobiele apparaat + Let op: een afgedrukt label hergebruiken is een overtreding van onze servicevoorwaarden en kan leiden tot strafrechtelijke vervolging. + Vanuit hier kan je het verzendlabel opnieuw afdrukken of het papierformaat van het label wijzigen. + Je verzendlabel kan worden afgedrukt + U kunt deze bestelling alleen op het web bewerken, omdat het web gebruikmaakt van %1$s en uw site gebruikmaakt van %2$s + Bezorgservice + Snelste + Voordeligste + Label aanschaffen + Label aanschaffen %1$s + Markeer deze bestelling als voltooid en informeer de klant + Verzendkosten + Bestelgegevens + Verzendingsgegevens + Voer de afmetingen van je pakket in of kies een optie voor een pakket via vervoerder om de beschikbare verzendkosten te bekijken. + Selecteer een pakket om de verzendkosten te bekijken + Een pakket selecteren + Ben je van plan om gevaarlijke goederen of materialen te verzenden? + Artikelenkaart in-/uitvouwen + %1$s  ·  %2$s + Gesorteerd op 1%s + Nee Sla mijn selectie op voor toekomstige campagnes <b>Goed voor:</b> %s Doel selecteren %s @@ -554,7 +590,7 @@ Language: nl Betaling innen De code moet de volgende indeling hebben: XXXX-XXXX-XXXX-XXXX Voer code in - Coupon + Coupons Thema\'s laden mislukt. Configuratie voltooid Aantal bijwerken ongedaan gemaakt @@ -3637,6 +3673,7 @@ Language: nl Belastingen Betaling Verzending + Totaal -%1$s%2$s %1$s%2$s Bestellingen diff --git a/WooCommerce/src/main/res/values-pt-rBR/strings.xml b/WooCommerce/src/main/res/values-pt-rBR/strings.xml index 70b55459058..41353600f93 100644 --- a/WooCommerce/src/main/res/values-pt-rBR/strings.xml +++ b/WooCommerce/src/main/res/values-pt-rBR/strings.xml @@ -1,11 +1,47 @@ + Envelope + Caixa + Adicionar pacote + Salvar isto como um novo modelo de pacote + Altura + Largura + Comprimento + Tipo de pacote + Salvo + Transportadora + Personalizado + Solicitar reembolso + Agendar coleta + Rastrear envio + Saiba como imprimir do seu dispositivo móvel + Observação: reutilizar uma etiqueta impressa é uma violação dos nossos termos de serviço e pode resultar em acusações criminais. + Aqui você pode imprimir a etiqueta de envio novamente ou alterar o tamanho do papel da etiqueta. + Sua etiqueta de envio está pronta para impressão + Você só pode editar este pedido no navegador Web, pois ele usa %1$s, e a moeda do seu site é %2$s + Serviço de entrega + Mais rápido + Mais barato + Comprar etiqueta + Comprar etiqueta · %1$s + Marcar este pedido como concluído e notificar o cliente + Frete + Detalhes do pedido + Detalhes do envio + Insira as dimensões do seu pacote ou escolha uma opção de pacote de transportadora para ver as taxas de envio disponíveis. + Selecione um pacote para ver as taxas de envio + Selecione um pacote + Você está enviando mercadorias ou materiais perigosos? + Ocultar/mostrar cartão de itens + %1$s  ·  %2$s + Não + Ordenado por 1%s Salvar minha seleção para campanhas futuras <b>Uma boa opção para:</b> %s Selecionar objetivo %s @@ -554,7 +590,7 @@ Language: pt_BR Receber pagamento O código deve estar no formato XXXX-XXXX-XXXX-XXXX Digite o código - Cupom + Cupons Falha ao carregar temas. Configuração concluída Atualização de quantidade desfeita @@ -3631,6 +3667,7 @@ Language: pt_BR Impostos Pagamento Envio + Total -%1$s%2$s %1$s%2$s Pedidos diff --git a/WooCommerce/src/main/res/values-ru/strings.xml b/WooCommerce/src/main/res/values-ru/strings.xml index 7cc5d5626cf..d54e1742733 100644 --- a/WooCommerce/src/main/res/values-ru/strings.xml +++ b/WooCommerce/src/main/res/values-ru/strings.xml @@ -1,11 +1,47 @@ + Конверт + Коробка + Добавить упаковку + Сохранить как новый шаблон упаковки + Высота + Ширина + Длина + Тип упаковки + Сохранено + Перевозчик + Произвольный + Запросить возврат средств + Запланировать самовывоз + Отслеживать доставку + Как распечатывать файлы с мобильного устройства + Примечание. Повторное использование напечатанной этикетки запрещается условиями предоставления услуг и может повлечь уголовное преследование. + Здесь вы можете заново напечатать транспортную этикетку или изменить формат бумаги для этикетки. + Ваша транспортная этикетка готова к печати + К сожалению, этот заказ можно редактировать только в Интернете, так как он сделан в %1$s, а валюта вашего сайта — %2$s + Служба доставки + По скорости + Купить этикетку + Купить этикетку · %1$s + По стоимости + Отметить заказ как выполненный и уведомить заказчика + Стоимость доставки + Введите размеры посылки или выберите одну из упаковок перевозчика, чтобы узнать доступные тарифы на доставку. + Выберите упаковку, чтобы узнать тарифы + Выберите упаковку + Имеются ли в вашем отправлении опасные товары или материалы? + Сведения о заказе + Сведения о доставке + Свернуть/развернуть карточку товара + %1$s  ·  %2$s + Нет + Отсортировано по 1%s Сохранить выбор для будущих кампаний <b>Подходит для:</b> %s Выбрать цель %s @@ -31,8 +67,8 @@ Language: ru Нет фотографий Фотографии товара Выберите имеющееся фото товара - Недопустимый ключ: удалите символ «_» в самом начале. Этот ключ уже применяется в другом произвольном поле.\nВ настоящий момент приложение не поддерживает создание дубликатов ключей. При необходимости создать дубликат ключа воспользуйтесь wp-admin. + Недопустимый ключ: удалите символ «_» в самом начале. Добавить произвольные поля Произвольное поле удалено Не удалось сохранить изменения. Повторите попытку @@ -53,21 +89,21 @@ Language: ru Ежедневные затраты Сколько вы планируете потратить на кампанию и сколько времени она должна продлиться? %1$s ➔ %2$s - При помощи Blaze демонстрируйте ваши товары миллионам потенциальных покупателей и повышайте продажи Думаете о том, как повысить продажи? + При помощи Blaze демонстрируйте ваши товары миллионам потенциальных покупателей и повышайте продажи Ошибка при загрузке произвольных полей Произвольные поля Затемнённый фон. Коснитесь, чтобы закрыть диалог. %1$s в неделю Выполнять до остановки мною - Запущена %1$s - еженедельные расходы %1$s еженедельно начиная с %2$s Еженедельно Осталось Итого Переходы По-видимому, ваше устройство находится в режиме экономии энергии. \nПока этот режим активен, сведения о магазине будут недоступны + Запущена %1$s + еженедельные расходы Всплывающее меню с опциями. Смахивайте товары, чтобы переходить к следующим. Открыть меню панели инструментов Панель инструментов со статусом платёжного терминала. Меню открыто. Дважды коснитесь, чтобы начать работу. @@ -99,13 +135,13 @@ Language: ru Новый заказ ОК + Создать заказ в разделе «Управление магазином» - Чтобы принять платёж за товар, не относящийся к простым, выйдите из режима POS и создайте новый заказ в таблице заказов. Почему я не вижу свои товары? Информация Закрыть - Подробнее В данный момент POS поддерживает только простые материальные товары. Другие типы товаров, в частности виртуальные и вариативные товары, станут доступны в ближайших обновлениях. Только простые товары + Чтобы принять платёж за товар, не относящийся к простым, выйдите из режима POS и создайте новый заказ в таблице заказов. + Подробнее Адрес сайта Google для WooCommerce Добавить платную кампанию @@ -115,12 +151,12 @@ Language: ru Ваша новая кампания создана. Впереди у вас удачный сезон продаж! Всё готово! Не удалось создать заказ - Повторить попытку Значок ошибки Хотите повторить попытку? Ошибка при загрузке товаров В данный момент POS поддерживает только простые товары В данный момент POS поддерживает только простые товары — \nсначала создайте такой товар. + Повторить попытку Нет поддерживаемых товаров Товаров нет Поддержка @@ -192,35 +228,35 @@ Language: ru Имя, содержание и описание Можно отредактировать или восстановить сведения о товаре перед сохранением. Программы - Кампании Google Нет программ за этот период + Кампании Google Подключить Корзина Создание сведений о товаре Считывать текст с фотографии товара Например: «Чёрная футболка, х/б, мягкая ткань, прочные швы, уникальный дизайн» - Расскажите нам о своём товаре и его достоинствах, а потом ИИ сотворит для вас чудо. Исходные данные Мы сгенерируем для вас сведения о товаре + Расскажите нам о своём товаре и его достоинствах, а потом ИИ сотворит для вас чудо. Получение платежа по карте Итого - Налоги Подытог Оплата прошла успешно Платёж не выполнен. Повторите попытку. Значок корзины Товары - Товары (%d) - Очистить Повышайте продажи и привлекайте больше посетителей при помощи Google Ads Google для WooCommerce Нет правил количества + Товары (%d) + Очистить + Налоги Аудитория Отмена - Выход Закрыть POS - Удалить %s из корзины Оформление заказа + Удалить %s из корзины + Выход Статус считывающего устройства неизвестен Оформление заказа Считывающее устройство подключено @@ -258,8 +294,8 @@ Language: ru Не удалось загрузить самые продаваемые товары Н/Д Сумма сдачи - Полученные наличные Самые активные купоны + Полученные наличные Получить оплату (%s) Посмотреть все отзывы Не найдено ни одного отзыва, соответствующего выбранному фильтру. Попробуйте изменить фильтр. @@ -288,8 +324,8 @@ Language: ru Скрыть %s Завершено Обратная связь - Убедитесь, что на сайте используется последняя версия WooCommerce и аналитика WooCommerce активирована. Не удалось отобразить\n аналитику вашего магазина + Убедитесь, что на сайте используется последняя версия WooCommerce и аналитика WooCommerce активирована. Посмотреть все задачи Аналитические данные сеанса основываются на количестве уникальных посетителей, которое невозможно определить для произвольных временных промежутков. Данные сеанса недоступны @@ -302,11 +338,11 @@ Language: ru Отмена Всё равно выйти Похоже, вы ещё не одобрили соединение с приложением. Вы уверены, что хотите выйти? - Выберите изображение размером минимум 400x400 пикселей Недопустимое изображение Судя по всему, введённые вами имя пользователя или пароль неверны. Проверьте учётные данные и повторите попытку. Если ваши данные по-прежнему не загружаются, обратитесь за помощью в службу поддержки. Проблем с подключением нет + Выберите изображение размером минимум 400x400 пикселей Вернуться на предыдущий экран Повторить попытку подключения Идёт подключение к вашему сайту @@ -320,15 +356,15 @@ Language: ru Продолжить Если у вас возникают проблемы, обратитесь в нашу службу поддержки. 3. После установки подключения вы автоматически выполните вход в свой магазин. - 2. Когда появится запрос, подтвердите подключение, нажав кнопку подтверждения. 1. Сначала войдите с учётными данными вашего сайта. Следуйте этой процедуре, чтобы напрямую подключить приложение Woo к вашему магазину при помощи пароля приложения. - Возможно, это потому, что в вашем магазине действуют дополнительные меры безопасности. Не удалось войти в ваш магазин Когда вы сделаете заказ, сведения о нём отобразятся здесь. Сведений о заказе ещё нет Добавить индивидуальную сумму Чтобы указать сумму платежа, добавьте\nиндивидуальную сумму к своему заказу. + 2. Когда появится запрос, подтвердите подключение, нажав кнопку подтверждения. + Возможно, это потому, что в вашем магазине действуют дополнительные меры безопасности. Мы объединили получение платежа и\nсоздание заказа, сделав операцию более доступной\nи эффективной. Получение платежа \nперемещено Комплекты @@ -351,16 +387,14 @@ Language: ru Доступно обновление (%s) Обновлён Название магазина + Не удалось загрузить предлагаемые домены Удалить рубрику Обновить рубрику Ошибка при удалении рубрики Рубрика товаров удалена Рубрика товаров обновлена - Не удалось загрузить предлагаемые домены Варианты Укажите домен - Выберите домен - Просмотреть всю аналитику магазина По годам По месяцам По неделям @@ -370,6 +404,8 @@ Language: ru Подключить другой магазин Запускаете новый магазин? Название магазина + Выберите домен + Просмотреть всю аналитику магазина Пожалуйста, подождите… Обновление статусов наличия на складе Что-то пошло не так. Повторите попытку. @@ -383,10 +419,8 @@ Language: ru Товары (%1$d) с управляемым количеством на складе будут пропущены. Статус наличия на складе будет обновлен для %1$d товаров. Текущий статус наличия на складе: %1$s - Текущий статус наличия на складе разнороден ГОТОВО Обновить статус наличия на складе - Войти с учётными данными сайта Версия WooCommerce Установленные плагины Плагины @@ -399,18 +433,20 @@ Language: ru Детали заказа Ошибка при отправке заказа в корзину Заказ отправлен в корзину + Текущий статус наличия на складе разнороден + Войти с учётными данными сайта Похоже, с вашим сайтом возникла проблема.\n\nЧтобы решить эту проблему, обратитесь к своему хостинг-провайдеру. + Похоже, вы не подключены к Интернету.\n\nУбедитесь, что ваш Wi-Fi включён. Если вы используете мобильные данные, убедитесь, что они включены в настройках вашего устройства. Похоже, возникла проблема при подключении к Jetpack.\n\nНо не волнуйтесь: наши инженеры поддержки вам помогут. Свяжитесь с нами, и мы будем рады помочь. Похоже, нам не удаётся правильно обработать ответ вашего сайта.\n\nНо не волнуйтесь: наши инженеры поддержки вам помогут. Свяжитесь с нами, и мы будем рады помочь. Похоже, ваш сайт отвечает слишком долго.\n\nЧтобы решить эту проблему, обратитесь к своему хостинг-провайдеру. - Похоже, вы не подключены к Интернету.\n\nУбедитесь, что ваш Wi-Fi включён. Если вы используете мобильные данные, убедитесь, что они включены в настройках вашего устройства. - Товар не выбран Читать далее Поддержка - Получение заказов с вашего сайта - Подключение к серверам WordPress.com Подключение к Интернету Добавить статистику за выбранный период + Товар не выбран + Получение заказов с вашего сайта + Подключение к серверам WordPress.com Местоположение не найдено.\nПовторите попытку. Просмотры страниц сеанса Тип устройства @@ -429,13 +465,13 @@ Language: ru Атрибуция заказа Связаться в Telegram Связаться в WhatsApp - Идентификатор: %d Клиент Товар Гость Этот пользователь — гость, а гостевой статус не позволяет фильтровать заказы. Повторите попытку позже или свяжитесь с нами. Мы будем рады помочь! Ваш сайт отвечает долго + Идентификатор: %d Показать подробности Налог на доставку Настроить аналитику @@ -451,8 +487,6 @@ Language: ru Готово Мы проверяем вашу кампанию. Она будет опубликована в течение 24 часов. Впереди у вас удачный сезон продаж! Всё готово! - Ключ уже существует - Слишком длинный конечный URL-адрес Значение Ключ Размещение: %s @@ -469,6 +503,8 @@ Language: ru Добавьте ключевую фразу и описание кампании Blaze Добавить изображение Добавьте изображение для кампании Blaze + Ключ уже существует + Слишком длинный конечный URL-адрес Перетащить указатель Карты аналитики Смотреть отчет @@ -477,18 +513,18 @@ Language: ru Параметры URL-адреса URL-адрес назначения Ввести вручную - Не удалось выполнить поиск.\nПовторите попытку Начните набирать название страны, штата или города, чтобы увидеть доступные варианты Нажимая «Отправить кампанию», вы принимаете <a href=\'termsOfService\'><u>условия предоставления услуг</u></a> и <a href=\'advertisingPolicy\'><u>политику публикации рекламы</u></a>, а также разрешаете использовать указанный способ оплаты для списания средств за выбранные вами бюджет и период. <a href=\'learnMore\'><u>Подробнее</u></a> о том, как использовать бюджеты и платежи за продвигаемые записи. + Не удалось выполнить поиск.\nПовторите попытку Отправить кампанию Не удалось загрузить способы оплаты. Чтобы повторить попытку, нажмите здесь. Добавить способ оплаты - Загрузка способов оплаты Итого Кампания Blaze Итоговые суммы платежей Оплата Поиск местоположений + Загрузка способов оплаты Не удалось сохранить чек Не удалось загрузить чек Не удалось обнаружить ни одного приложения, в котором можно опубликовать чек @@ -499,7 +535,6 @@ Language: ru Ключевая фраза Изменить изображение Применить - Дата начала %1$s дн. Раздел «Показы» отражает частоту, с которой ваша реклама появляется на экранах потенциальных клиентов.\n\n\n Достичь этой цифры в точности будет невозможно из-за колебаний посещаемости и различного поведения пользователей, однако мы стремимся к тому, чтобы реальное число показов рекламы максимально приближалось к целевому показателю.\n\n\n Учитывайте, что показы влияют лишь на видимость рекламы, а не на действия читателей. Готово @@ -507,11 +542,12 @@ Language: ru Обновить Изменить Приблизительный ежедневный охват пользователей - %1$s ежедневно на %1$s дн. Настройте бюджет Все %1$s дн. с %2$s + %1$s ежедневно + Дата начала Больше не показывать Напомнить позже Есть свободная минутка? Оставьте краткий отзыв и помогите нам улучшить функции на базе ИИ. @@ -524,11 +560,11 @@ Language: ru Бюджет Сведения Купить сейчас - Редактировать рекламное объявление Предварительный просмотр + Редактировать рекламное объявление Отключено - Выбор товара Выбрать товар %s + Выбор товара <b>В прямом эфире:</b> следите за началом вашей кампании и её успехами. <b>Быстрый просмотр:</b> отправьте свою рекламу на оперативную модераторскую проверку. <b>Создание бюджета:</b> определите продолжительность кампании и затраты на неё. @@ -536,12 +572,12 @@ Language: ru <b>Выбор товара:</b> выберите, что рекламировать при помощи Blaze. Управление запасами Запасы не управляются - Как работает Blaze Запустите кампанию Ваша реклама появится на миллионах сайтов в сетях WordPress.com и Tumblr. Охватите широкую аудиторию - «Наш инструмент покажет ваш товар именно там, где его смогут увидеть заинтересованные покупатели». Простота глобального охвата + «Наш инструмент покажет ваш товар именно там, где его смогут увидеть заинтересованные покупатели». + Как работает Blaze Запуск рекламы за несколько минут: вам не понадобится ни навык, ни солидный бюджет, можно начать всего с 5 долларов США в день. Быстрый старт, значительный эффект Наш инструмент разработан специально для того, чтобы дать продавцам возможность простой и быстрой настройки рекламных кампаний с целью максимального увеличения посещаемости. @@ -554,28 +590,28 @@ Language: ru Получение платежа Код должен вводиться в формате XXXX-XXXX-XXXX-XXXX Введите код - Купон + Купоны Не удалось загрузить темы. Настройка выполнена Обновление количества отменено Не удалось загрузить текущую тему ПК Планшет - Мобильный телефон нажмите здесь - При загрузке шаблона возникла проблема. %1$s для демонстрационного режима. Найдите самую подходящую для вас тему в магазине тем WooCommerce. Текущая тема Попробуйте новый дизайн Начать опрос - Мы высоко ценим ваше мнение! - Активация функции очной оплаты даёт возможность клиенту оплачивать заказ при доставке наличными или банковской картой.\n\nЗаказы можно по-прежнему создавать вручную, не активируя этой функции. Хотите добавить функцию очной оплаты к оформлению заказа онлайн? Требуется помощь? <a href=\'\'>Свяжитесь с нами</a> + Мобильный телефон + При загрузке шаблона возникла проблема. %1$s для демонстрационного режима. + Мы высоко ценим ваше мнение! + Активация функции очной оплаты даёт возможность клиенту оплачивать заказ при доставке наличными или банковской картой.\n\nЗаказы можно по-прежнему создавать вручную, не активируя этой функции. Возместить индивидуальную сумму Возврат индивидуальной суммы - Сканировать штрихкод товара Добавить подарочную карту + Сканировать штрихкод товара Товар Количество Исходное количество @@ -587,35 +623,35 @@ Language: ru Товар с артикулом %s не значится в складских запасах. Повторите попытку. Товар с артикулом %s не найден. Повторите попытку. Не удалось активировать тему, повторите попытку. - Звуковое оповещение о новых заказах отключено. Включите его заново, чтобы слышать «дзинь» всякий раз при очередной продаже. - Включить «дзинь» Сканировать штрихкод, чтобы обновить запас - Это тестовое оповещение для проверки звука «дзинь».\nМожете его удалить. Тестировать уведомление ТЕСТИРОВАТЬ ЗВУК - Всё готово! Теперь звук «дзинь» будет раздаваться при каждом заказе. ОТКЛЮЧИТЬ ЗВУК ВКЛЮЧИТЬ ЗВУК - Включите заново, чтобы слышать «дзинь» при каждой новой продаже. Отслеживайте заказы ваших клиентов! - Звук «дзинь» отключён Количество заказов - % 0 Процент от общей суммы заказа + Звуковое оповещение о новых заказах отключено. Включите его заново, чтобы слышать «дзинь» всякий раз при очередной продаже. + Включить «дзинь» + Это тестовое оповещение для проверки звука «дзинь».\nМожете его удалить. + Всё готово! Теперь звук «дзинь» будет раздаваться при каждом заказе. + Включите заново, чтобы слышать «дзинь» при каждой новой продаже. Отслеживайте заказы ваших клиентов! + Звук «дзинь» отключён + % Фиксированная сумма Как вы хотите добавить индивидуальную сумму? - Процент от общей суммы заказа (%1$s) Удалить индивидуальную сумму - Тема успешно активирована + Процент от общей суммы заказа (%1$s) Главная страница Коснитесь для просмотра Страницы в этом шаблоне Предварительный просмотр + Тема успешно активирована Ищете что-то другое? Вы можете изменить настройки в любой момент. - Выберите тему Темы Узнайте больше! + Выберите тему Требуется настройка Скрыть Blaze Благодарственная записка, созданная ИИ @@ -624,69 +660,69 @@ Language: ru Создать повторно ✨ Создание благодарственной записки к вашему заказу… Благодарственная записка - Примечание. Чтобы можно было включить этот параметр, в тарифном плане не должно быть бесплатного пробного периода или синхронизированной даты продления. Включите этот параметр, чтобы взимать плату за доставку только один раз при первоначальном заказе. + Примечание. Чтобы можно было включить этот параметр, в тарифном плане не должно быть бесплатного пробного периода или синхронизированной даты продления. Включено - Единовременная доставка Документы и другие файлы на устройстве + Единовременная доставка ✨Создать благодарственную записку Удержать налоги Доступные средства вносятся на счёт автоматически раз в %s. Доступные средства вносятся на счёт автоматически раз в день. Денежные средства станут доступны после утверждения в течение %d дн. Выбрать вариант - Выберите вариант + Выберите %1$s + %d элементов «%1$s» -> %2$s выберите конкретный вариант Выбрано элементов: %1$s Выбран %1$s элемент - Выберите %1$s более %1$s элементов более %1$s элемента менее %1$s элементов от %1$s до %2$s элементов - %d элементов %d элемент + Выберите вариант Измените количество товара с %1$.2f на %2$.2f - Сохранить конфигурацию Конфигурация - Товар %s - Настроить - Необязательно; регистрационный сбор взимается немедленно, даже если у товара есть бесплатный пробный период или синхронизированы даты оплаты. Подписка на продукт с вариантами Продукт по подписке с вариантами Уникальная подписка на продукт, включающая регулярные платежи Продукт по простой подписке + Сохранить конфигурацию + Товар %s + Настроить + Необязательно; регистрационный сбор взимается немедленно, даже если у товара есть бесплатный пробный период или синхронизированы даты оплаты. Необязательный период времени до списания первого регулярного платежа. Любой регистрационный взнос всё равно будет взиматься в начале подписки. Пробный период не может превышать: 90 дней, 52 недели, 24 месяца или 5 лет. - Пробный период действия тарифного плана Срок действия подписки истекает + Пробный период действия тарифного плана + ТОВАР ИНДИВИДУАЛЬНЫЕ СУММЫ ИТОГОВЫЕ СУММЫ ПЛАТЕЖЕЙ ПРИМЕЧАНИЯ К ЗАКАЗУ ТОВАРЫ - ТОВАР КЛИЕНТ Пожалуйста предоставьте ключ безопасности для продолжения. Возникла проблема со входом в систему с помощью ключа безопасности Использовать ключ безопасности Период - Расчётный интервал Распродажа Неизвестно Сбой Отменено В процессе перехода - На утверждении Оплачено Ожидается - Свернуть/развернуть выписку по счёту Узнайте, когда вы сможете получить ваши средства - Доступные средства вносятся на счёт автоматически каждый месяц %s. - Денежные средства станут доступны после утверждения в течение %d дн. + Расчётный интервал + На утверждении + Свернуть/развернуть выписку по счёту Средства на утверждении Доступные средства Налоги Товары + Денежные средства станут доступны после утверждения в течение %d дн. + Доступные средства вносятся на счёт автоматически каждый месяц %s. Итоговые суммы платежей Адрес электронной почты или имя пользователя Не удалось создать заказ с индивидуальной суммой @@ -713,8 +749,8 @@ Language: ru Текст не обнаружен. Выберите другую фотографию упаковки или введите сведения о товаре вручную. Добавить товар Сканировать штрихкод - Свернуть/развернуть карточку товара Уменьшить количество товара + Свернуть/развернуть карточку товара Увеличить количество товара Добавить индивидуальную сумму Цена со скидкой @@ -727,8 +763,8 @@ Language: ru Меняйте текст: отмените выбор ненужных отсканированных страниц или нажмите, чтобы отредактировать текст Ключевые слова Использовать фото упаковки (по желанию) - Выберите «Оплата в касание» в опциях получения платежей в\nсведениях о заказе или разделе «Меню > Платежи». Попробуйте оплатить %s банковской картой.\nПосле этого средства будут возвращены. + Выберите «Оплата в касание» в опциях получения платежей в\nсведениях о заказе или разделе «Меню > Платежи». Просто, безопасно и конфиденциально. Принимайте все виды очных платежей прямо\nна вашем телефоне. Дополнительное оборудование не требуется. Отклонено @@ -740,14 +776,14 @@ Language: ru Кампания Blaze Символ бесконтактной оплаты (Contactless Symbol) — торговая марка, принадлежащая компании EMVCo, LLC и используемая с её разрешения. 5. Если вы видите значок «Выполнено» в виде галочки, значит, магазин обрабатывает ваш платёж, а транзакция завершена. - 3. Покажите покупателю ваш смартфон. 2. Нажмите «Принять платёж» и выберите Tap to Pay. - 1. Создайте заказ + 3. Покажите покупателю ваш смартфон. Как это работает Подробнее об устройствах чтения карт Чтобы принимать платежи сверх лимита, вам может потребоваться устройство чтения карт, в котором можно вводить PIN-коды. Мы не поддерживаем ввод PIN-кодов при использовании функции Tap to Pay на устройствах на базе Android. В %1$s некоторые карты требуют ввода PIN-кода при бесконтактных транзакциях на сумму свыше %2$s. + 1. Создайте заказ Важная информация Функция Tap to Pay (Оплата в касание) позволяет принимать все виды бесконтактных платежей: от банковских карт до цифровых кошельков — без необходимости приобретать устройство чтения карт. Что такое Tap to Pay? @@ -791,40 +827,40 @@ Language: ru Добавить эту ставку ко всем созданным заказам Изменить налоговые ставки Изменить налоговые ставки в консоли + Способы оплаты Добавьте налоговые ставки в консоли. Будут показаны только налоговые ставки с информацией о местоположении. Налоговые ставки не найдены Посмотрите другие платёжные системы и \nвыберите одну из них. - Способы оплаты Изображения и видео на устройстве - Исправить Завершить настройку + Исправить Установить налоговую ставку Активировать Установить новую налоговую ставку - WooPayments Настроить + WooPayments Изменить налоговые ставки в консоли Адрес клиента будет изменён на адрес, где действует выбранная вами налоговая ставка. Кнопка открытия диалогового окна с информацией о налоговых ставках ВЫБРАТЬ НАЛОГОВУЮ СТАВКУ Не можете найти нужную налоговую ставку? + Изменить налоговые ставки в консоли + Налоги и налоговые ставки + Налоговые ставки для разных адресов можно изменить в консоли магазина. Сейчас налоговая ставка рассчитывается на основе адреса доставки%1$s Сейчас налоговая ставка рассчитывается на основе платёжного адреса%1$s Сейчас налоговая ставка рассчитывается на основе адреса магазина%1$s - Изменить налоговые ставки в консоли Кнопка «Изменить налоговые ставки в консоли» - Налоги и налоговые ставки - Налоговые ставки для разных адресов можно изменить в консоли магазина. Налоги рассчитываются на основе сопоставления платёжного адреса, адреса доставки или адреса магазина с адресом, где действует налоговая ставка. Сведения о налоговых ставках Используя WooCommerce Payments, вы принимаете наши <a href=\'termsOfService\'><u>Условия предоставления услуг</u></a> и подтверждаете, что ознакомились с <a href=\'privacyPolicy\'><u>Политикой конфиденциальности</u></a>. <a href=\'learnMore\'><u>Подробнее</u></a> о подтверждении вашей информации на WooPayments. Начать настройку Партнёр WooPayments — платёжная система Stripe. Вы будете перенаправлены на сайт Stripe для регистрации. Мы попросим вас подтвердить сведения о вашем бизнесе и платёжные данные. - Уведомления WooPayments будут приходить на адрес эл. почты, указанный в вашей учётной записи WordPress.com. Хотите использовать новую учётную запись? <a href=\'learnMore\'><u>Подробности см. здесь.</u></a> Перед началом настройки 4–6 минут Примерное время настройки + Уведомления WooPayments будут приходить на адрес эл. почты, указанный в вашей учётной записи WordPress.com. Хотите использовать новую учётную запись? <a href=\'learnMore\'><u>Подробности см. здесь.</u></a> Управляйте платежами без усилий с помощью WooPayments — всё на одной консоли. Принимайте карты, платежи Apple Pay, очные платежи и более 135 валют — без платы за настройку и ежемесячное использование. Не удалось сохранить название магазина. Повторите попытку. Сохранение нового названия магазина… @@ -833,16 +869,16 @@ Language: ru Обновить название магазина Поздравляем! Вы успешно прошли настройку — ваша платёжная система готова к работе. Готово! - Управляйте платежами с помощью WooPayments — без платы за настройку и ежемесячное использование. Настройки учётной записи Выбрать категорию - Категория опасных веществ DHL Express. В настоящее время WooCommerce Shipping не поддерживает доставку опасных веществ через %1$s - Инструмент поиска опасных веществ USPS. С помощью %1$s выясните, можно ли доставить ваш товар по почте. www.usps.com/hazmat. Узнайте, как надежно упаковать, выполнить адресацию и доставить опасные вещества с помощью USPS® в %1$s + Управляйте платежами с помощью WooPayments — без платы за настройку и ежемесячное использование. + Категория опасных веществ + Инструмент поиска опасных веществ USPS. Вычислено на основе адреса доставки Вычислено на основе платёжного адреса Вычислено на основе адреса магазина @@ -850,16 +886,16 @@ Language: ru Общая сумма заказа Расчётный процент Расчётная сумма - Название магазина Правильный выбор названия магазина может помочь в поисковой оптимизации. + Название магазина Назовите магазин Включите NFC Посылка, небольшое количество (требуется маркировка) - Наземное отправление, ограниченное количество: аэрозоли, дезинфицирующие спреи, аэрозольная краска, спреи для волос, пропан, бутан, чистящие средства и т. д. — Духи, лак для ногтей, жидкость для снятия лака для ногтей, растворители, антисептики для рук, медицинский спирт, продукты на основе этанола и т. д. — Другие поверхностные вещества в ограниченном количестве (косметика, бытовая химия, краски и т. д.) Посылка с зажигающим устройством (разрешённым к перевозке) + Наземное отправление, ограниченное количество: аэрозоли, дезинфицирующие спреи, аэрозольная краска, спреи для волос, пропан, бутан, чистящие средства и т. д. — Духи, лак для ногтей, жидкость для снятия лака для ногтей, растворители, антисептики для рук, медицинский спирт, продукты на основе этанола и т. д. — Другие поверхностные вещества в ограниченном количестве (косметика, бытовая химия, краски и т. д.) + Посылка с допустимым количеством (например, небольшой объём воспламеняющейся жидкости, коррозионно-активные, токсичные или экологически опасные вещества — требуется маркировка) Посылка с потребительскими товарами ID8000 — разрешённые для авиаперевозки потребительские товары ID8000 (невоспламеняющиеся аэрозоли, воспламеняющиеся горючие жидкости, токсичные вещества, опасные материалы) Опасные материалы, разрешённые только для наземной перевозки (для товаров, которые не перечислены, но их можно перевозить только по земле) - Посылка с допустимым количеством (например, небольшой объём воспламеняющейся жидкости, коррозионно-активные, токсичные или экологически опасные вещества — требуется маркировка) П. 6.2 — посылка с опасными веществами — биологические вещества (например, наборы для лабораторных анализов, материалы для анализа на COVID) П. 6.1 — посылка с токсичными веществами (средняя летальная доза 50 мн/кг и менее) (пестициды, гербициды и т. д.) П. 5.2 — посылка с органическими пероксидами @@ -884,33 +920,33 @@ Language: ru К потенциально опасным материалам относятся батарейки и аккумуляторы, сухой лёд, воспламеняющиеся жидкости, аэрозоли, боеприпасы, фейерверки, лаки для ногтей, парфюм, краски, растворители и т. д. Опасные товары должны находиться в отдельных упаковках. Содержит опасные вещества Введите название товара. - Платформа электронной коммерции, которая растёт вместе с вами Переменная подписка - Удалить купон + Платформа электронной коммерции, которая растёт вместе с вами Все любят скидки Вы не создали ни одного купона. Создайте купон, чтобы применить его к этому заказу. Перейти к купонам Выберите купон - Не удалось создать купон + Удалить купон Купон создан Создать Создать купон - Создать %1$s Изменить купон Создайте фиксированную скидку на выбранные товары + Не удалось создать купон + Создать %1$s Создайте фиксированную скидку на всю корзину Создайте скидку в процентах на выбранные товары Фиксированная скидка на товар Фиксированная скидка на сумму корзины Процент скидки - Тип купона — фиксированный на товар - Тип купона — фиксированный на корзину - Тип купона — процент скидки Создать купон Добавить купон Создать тестовый заказ - Попробуйте вернуть средства за тестовый заказ в приложении Оплатите заказ и дождитесь push-уведомления в приложении WooCommerce. + Тип купона — фиксированный на товар + Тип купона — фиксированный на корзину + Тип купона — процент скидки + Попробуйте вернуть средства за тестовый заказ в приложении Выберите тестируемый товар, добавьте его в корзину и оформите заказ в магазине, как настоящий покупатель. Нажмите кнопку ниже, чтобы перейти в онлайн-магазин в браузере. Оформите тестовый заказ @@ -926,23 +962,23 @@ Language: ru Помогите нам понять ваши решения в отношении подписки. Ваша обратная связь очень важна. Отсутствует адрес электронной почты Отсутствует ФИО - Поиск существующего клиента или Последнее обновление %s (обновление каждые 30 минут) Последнее обновление %s + Поиск существующего клиента или <a href=\'\'>Узнайте больше</a> о том, как принимать оплату в касание на Android Получение платежей Нельзя добавить товар, не указав цену Нельзя добавить неопубликованный товар добавить клиента - Перейти в настройки Отмена + Не удалось проверить код купона. Повторите попытку + Не удалось найти купон с таким кодом. Повторите попытку + Сумма (%1$s) + Перейти в настройки Разрешить Вы запретили доступ к камере. Он необходим, чтобы сканировать штрихкод. Предоставьте доступ в настройках приложения Разрешите доступ к камере, чтобы сканировать штрихкод Предоставьте доступ к камере - Не удалось проверить код купона. Повторите попытку - Не удалось найти купон с таким кодом. Повторите попытку - Сумма (%1$s) Скидка %1$s – %1$s Сумма скидки @@ -950,8 +986,8 @@ Language: ru Сумма (%1$s) Не удалось применить скидку вручную. Сначала удалите купоны Сумма скидки не является допустимым числом - Скидка не может быть больше цены Удалить скидку + Скидка не может быть больше цены Текст кнопки Текст всплывающей подсказки. \n Может занимать несколько строк. Заголовок всплывающей подсказки @@ -963,8 +999,8 @@ Language: ru Описание создано ИИ На основе ИИ. <a href=\'\'><u>Подробнее</u></a>. К сожалению, в вашей стране оплата в касание на Android пока не поддерживается. Следите за новостями! - Чтобы использовать оплату в касание на Android, на устройстве должны быть установлены службы Google Play. Чтобы принимать очные платежи, установите службы Google Play или купите терминал с поддержкой Bluetooth. Чтобы использовать оплату в касание на Android, требуется Android 10 или более новой версии. Чтобы принимать очные платежи, обновите Android или купите терминал с поддержкой Bluetooth. + Чтобы использовать оплату в касание на Android, на устройстве должны быть установлены службы Google Play. Чтобы принимать очные платежи, установите службы Google Play или купите терминал с поддержкой Bluetooth. Чтобы использовать оплату в касание на Android, устройство должно быть оснащено модулем NFC. Чтобы принимать очные платежи, купите терминал с поддержкой Bluetooth. Оплата в касание недоступна См. требования @@ -984,9 +1020,9 @@ Language: ru Сканировать штрихкод Имя пользователя Имя - Эл. почта Использованы купоны Другие настройки + Эл. почта Возможно, позже Написать снова Требуется PIN-код, но функция оплаты касанием пока не поддерживает его. Подумайте об использовании внешнего устройства чтения карт @@ -995,22 +1031,19 @@ Language: ru Не удалось создать сообщение о публикации. Повторите попытку. Подробнее о функции ИИ Добавить дополнительное сообщение - Написание… Написать с помощью ИИ Продвигайте товары с помощью Blaze Blaze Доступен генератор контента на основе ИИ Продвигайте с помощью Blaze + Написание… Опубликовать товар Поздравляем! Вы стали на шаг ближе к открытию нового магазина. Первый товар создан 🎉 Система закрыла приложение Woo, когда оно работало в фоновом режиме. Вы можете попробовать зайти в него ещё раз. Система закрыла приложение Woo, когда оно работало в фоновом режиме. Вы можете попробовать зайти в него ещё раз. Карта извлечена слишком быстро - Товар с вариациями - В нашей политике конфиденциальности описано, как мы и другие поставщики используем файлы cookie и как вы можете ими управлять. Политика использования файлов cookie - Ваши сведения помогают нам повышать качество наших продуктов, ускорять их вывод на рынок и подстраивать WooCommerce под вас. Политика конфиденциальности При сохранении параметров конфиденциальности произошла ошибка. Сохранить @@ -1018,16 +1051,16 @@ Language: ru Помогите нам оптимизировать сервисы. Для этого мы собираем информацию о том, что пользователи делают в наших мобильных приложениях. Аналитика Управление конфиденциальностью + Товар с вариациями + В нашей политике конфиденциальности описано, как мы и другие поставщики используем файлы cookie и как вы можете ими управлять. + Ваши сведения помогают нам повышать качество наших продуктов, ускорять их вывод на рынок и подстраивать WooCommerce под вас. Ваша конфиденциальность очень важна для нас. Мы используем, храним и обрабатываем ваши личные данные, чтобы оптимизировать наше приложение (и вашу работу). В некоторых случаях ваши данные необходимы для работы системы, а в других случаях вы можете изменить в меню \"Настройки\" варианты их использования. Чтобы помочь нам повысить качество работы приложения и устранить возможные ошибки, включите автоматические отчёты о сбоях. - Сообщать о сбоях - Отчёты Узнайте больше о нашей политике конфиденциальности и политике использования файлов cookie. Политика конфиденциальности и политика использования файлов cookie Конфиденциальность Узнайте больше о данных, которые мы собираем в вашем магазине, и о том, как вы можете управлять передачей этих данных. Отслеживание использования - Для пользователей woocommerce.com доступны дополнительные опции конфиденциальности. Подробности см. здесь. Интернет-опции Дополнительные параметры конфиденциальности При обновлении настроек конфиденциальности произошла ошибка @@ -1035,26 +1068,29 @@ Language: ru Помогите нам оптимизировать сервисы. Для этого мы собираем информацию о том, что пользователи делают в наших мобильных приложениях. Аналитика Отслеживание - Мы заботимся о вашей конфиденциальности. Персональные данные используются для оптимизации мобильных приложений, улучшения защиты, а также аналитики и повышения удобства работы. Система завершила работу приложения Woo в момент его работы в фоновом режиме. Вы можете попробовать зайти в него ещё раз. - Невозможно добавить товар с вариациями напрямую. Выберите конкретную вариацию Сбой сканирования. Повторите попытку позже + Сообщать о сбоях + Отчёты + Мы заботимся о вашей конфиденциальности. Персональные данные используются для оптимизации мобильных приложений, улучшения защиты, а также аналитики и повышения удобства работы. + Невозможно добавить товар с вариациями напрямую. Выберите конкретную вариацию Товар с артикулом %s не найден. Не удалось добавить в заказ + Для пользователей woocommerce.com доступны дополнительные опции конфиденциальности. Подробности см. здесь. Сбой сканирования. Повторите попытку позже Сканировать штрихкод Отправляя товары в страны, которые следуют таможенным правилам Европейского союза (ЕС), вы теперь должны точно и понятно описать каждую позицию. Так, при отправке одежды необходимо указать её тип (например, мужские рубашки, жилет для девочки, куртка для мальчика), чтобы описание было приемлемым. В ином случае может произойти задержка или приостановка доставки на таможне. Обратитесь в службу поддержки + Не удалось закрыть учётную запись Эту учётную запись нельзя закрыть, пока в ней есть активные магазины. При попытке закрыть учётную запись произошла ошибка. - Не удалось закрыть учётную запись Закрытие учётной записи… Навсегда закрыть учётную запись - Введите ваше имя пользователя для подтверждения закрытия Подтвердите закрытие учётной записи Закрыть учётную запись Сканируйте QR-код и следуйте инструкциям Сканируйте для оплаты Удалить купон из заказа + Введите ваше имя пользователя для подтверждения закрытия Купон (%1$s) –%1$s Добавить купон @@ -1063,9 +1099,9 @@ Language: ru Добавить товары с помощью сканера Закрыть Подробнее - Отправляя товары в страны, которые следуют таможенным правилам Европейского Союза (ЕС), вы должны точно и понятно описать каждую позицию. В ином случае может произойти задержка или приостановка доставки на таможне. Следите за обновлениями и повышайте безопасность магазина. Откройте возможности Jetpack. Уведомления о заказах и многое другое + Отправляя товары в страны, которые следуют таможенным правилам Европейского Союза (ЕС), вы должны точно и понятно описать каждую позицию. В ином случае может произойти задержка или приостановка доставки на таможне. Показать или скрыть список действий по настройке магазина Список действий по настройке магазина Вы можете снова посмотреть его в любое время, открыв «Меню > Настройки > Магазин» @@ -1083,10 +1119,10 @@ Language: ru Опция по умолчанию Опции компонентов Компоненты можно редактировать в веб-консоли. - %d компонента (-ов) - 1 компонент Настройки компонентов Компоненты + %d компонента (-ов) + 1 компонент Нам нужно ваше разрешение, чтобы отправлять на ваше устройство push-уведомления о новых заказах, отзывах и прочем. Уведомления Составной товар @@ -1100,7 +1136,6 @@ Language: ru Увеличивайте продажи с помощью специальных предложений Просматривайте магазин Следите за новостями - Управляйте магазином через консоль Общее Настройки Товары в комплекте можно редактировать в веб-консоли. @@ -1111,6 +1146,7 @@ Language: ru Нет максимума Нет минимума Комплект + Управляйте магазином через консоль Количество в комплекте Максимальное количество Минимальное количество @@ -1143,32 +1179,32 @@ Language: ru Активно Вы можете редактировать подписки на товары в веб-консоли. Без пробного периода - Бесплатная регистрация Никогда не истекает - %1$s кажд. %2$s %3$s - Кажд. %1$d %2$s Кажд. %1$s Номер подписки%1$d Подписка OK - От первой продажи до миллионной выручки: Woo — ваш помощник. Узнайте, почему продавцы построили на нашей платформе 3,4 млн. онлайн-магазинов. Подписка + Подписка + Бесплатная регистрация + %1$s кажд. %2$s %3$s + Кажд. %1$d %2$s + От первой продажи до миллионной выручки: Woo — ваш помощник. Узнайте, почему продавцы построили на нашей платформе 3,4 млн. онлайн-магазинов. Неправильный одноразовый код. Проверьте правильность введенных данных и повторите попытку. Сбой запроса SMS. Повторите попытку. Запрос SMS выполнен. Вам должно прийти сообщение с кодом. - Подписка Устройство чтения карт принимает платежи дебетовыми и кредитными картами. Их можно прикладывать, проводить или вставлять. Принимайте бесконтактные платежи прямо в телефоне. - Для получения платежей по карте используйте\nсвой телефон. Попробуйте прямо сейчас. - Отправить отзыв - Не удалось войти, поскольку не разрешается создавать пароль приложения. Получение сайта… + Не удалось войти, поскольку не разрешается создавать пароль приложения. + Отправить отзыв + Для получения платежей по карте используйте\nсвой телефон. Попробуйте прямо сейчас. + Загрузка… Произошла ошибка при получении веб-сайта Повторите попытку, используя страницу консоли Войти - Загрузка… - %s завершён Действие вашей подписки завершено, и теперь вам доступны не все функции. + %s завершён %1$d дн. 1 день Загрузка… @@ -1181,13 +1217,11 @@ Language: ru Ошибка при получении сведений о плане Вы оформили подписку на %1$s! У вас есть доступ ко всем функциям до %2$s. У вас закончился пробный период, доступ к функциям ограничен. Подпишитесь на %1$s прямо сейчас. - У вас идёт %1$d-дневный бесплатный пробный период. Бесплатный пробный период закончится через %2$s. Перейдите на платную подписку для доступа к новым функциям магазина. Статус подписки Устранение неполадок Текущий: %s Сообщить о проблеме с подпиской Перейти на платную подписку - Осталось от пробного периода: %1$s. Конец пробного периода Пробный период закончился. Произошли неожиданные ошибки. @@ -1201,13 +1235,15 @@ Language: ru Назад в Мой магазин URL-адрес рекомендации Опубликовать мой магазин - Чтобы запустить магазин, необходимо перейти на платный тарифный план. <u>Перейти</u> Поиск доменов + Чтобы запустить магазин, необходимо перейти на платный тарифный план. <u>Перейти</u> + У вас идёт %1$d-дневный бесплатный пробный период. Бесплатный пробный период закончится через %2$s. Перейдите на платную подписку для доступа к новым функциям магазина. + Осталось от пробного периода: %1$s. Не удалось войти. Код состояния: %1$s Не удалось войти, так как не удается найти URL-адрес администратора магазина Не удалось войти, так как не удается найти URL-адрес входа в магазин - Не удалось войти из-за неожиданного ответа сайта. Мы работаем над этой проблемой. Произошла ошибка. Повторите попытку позже. + Не удалось войти из-за неожиданного ответа сайта. Мы работаем над этой проблемой. Для вашей учётной записи есть требования на утверждении. Чтобы получать очные платежи, выполните эти требования. Оцените ваши впечатления от работы с аналитикой Нравится аналитика? @@ -1250,31 +1286,31 @@ Language: ru Получение статуса Jetpack Что-то пошло не так. Повторите попытку позже. Попробуйте выполнить платёж + Регистрация доменного имени… + Выберите страну + Выберите округ/область Получение платежей по карте\nна вашем телефоне Оплата в касание ДЕЙСТВИЯ Во время регистрации домена произошла ошибка - Выберите округ/область - Выберите страну - Регистрация доменного имени… - Зарегистрировать домен - Почтовый индекс - Область/округ (не доступно) - Округ/Область - Город - Адрес 2 - Адрес - Страна - Код страны Телефон - Организация (необязательно) + Код страны + Страна + Адрес + Адрес 2 + Город + Округ/Область + Область/округ (не доступно) + Почтовый индекс + Зарегистрировать домен Для вашего удобства, мы заполнили вашу контактную информацию WordPress.com. Пожалуйста, перепроверьте её на корректность, действительно ли вы хотите использовать её для этого домена. - Контактная информация домена - Зарегистрировать открыто - Зарегистрировать как личный с защитой персональных данных - Введите правильный %s - Регистрируя этот домен, вы соглашаетесь с нашими %1$sправилами и условиями%2$s + Организация (необязательно) Владельцы доменов должны делиться контактной информацией для публичной базы данных по всем доменам. С защитой персональных данных мы публикуем нашу информацию вместо вашей и перенаправляем вам все сообщения приватным образом. + Регистрируя этот домен, вы соглашаетесь с нашими %1$sправилами и условиями%2$s + Введите правильный %s + Зарегистрировать как личный с защитой персональных данных + Зарегистрировать открыто + Контактная информация домена Защита персональных данных Только администраторы магазина могут получить доступ к настройкам домена Или продолжите с помощью волшебной ссылки @@ -1307,11 +1343,11 @@ Language: ru Основной адрес сайта <a href=\'\'><u>Узнайте больше</u></a> о доменах и связанных с ними действиях. Поиск домена - Приобретённый домен будет перенаправлять пользователей на ваш основной адрес. Отправить заявку на домен На вашем тарифе можно бесплатно зарегистрировать домен на один год. Отправьте заявку на бесплатный домен Бесплатный адрес вашего магазина + Приобретённый домен будет перенаправлять пользователей на ваш основной адрес. Домены Больше не показывать Напомнить позже @@ -1333,19 +1369,19 @@ Language: ru Подождите Подготовка приложения для чтения карт… Приложение для чтения карт готово к работе - Устройство чтения карт Оплата в касание Коэффициент конверсии Сессии Нет сессий за этот период По сравнению с Домен + Устройство чтения карт Что такое пароли приложения? - Кажется, на вашем сайте %1$s отключена функция паролей приложения.\n Включите её, чтобы использовать приложение WooCommerce. Открыть страницу установки - При отправке ответа произошла ошибка - Ответ отправлен! + Кажется, на вашем сайте %1$s отключена функция паролей приложения.\n Включите её, чтобы использовать приложение WooCommerce. Ответить + Ответ отправлен! + При отправке ответа произошла ошибка Выбрать всё Обновить цену Обновить статус @@ -1356,57 +1392,57 @@ Language: ru Все варианты уже созданы. нет вариантов для создания Выбрать несколько - Нет доступных доменов по этому запросу Создание вариантов Будет создан вариант для каждой возможной комбинации атрибутов (всего: %1$d) Создать все варианты? Текущее максимальное количество создаваемых вариантов: %1$d. Количество вариантов, которые можно создать для этого продукта: %2$d. Превышено максимальное количество вариантов Создание вариантов для всех комбинаций ваших атрибутов. - Создать все варианты Создайте один новый вариант. Вручную выберите, какие атрибуты относятся к варианту продукта. Добавить новый вариант Добавить вариацию + Создать все варианты + Нет доступных доменов по этому запросу Выйти без подключения Продолжить подключение + Обратитесь к менеджеру магазина или администратору. Попробуйте подключиться ещё раз, чтобы войти в магазин. Jetpack установлен, но не подключён. У вас нет разрешения на подключение Jetpack к этому магазину - Обратитесь к менеджеру магазина или администратору. Отменить установку Повторить авторизацию Повторить активацию Повторить установку Получить поддержку - Повторите попытку и обратитесь в службу поддержки, если эта ошибка произойдёт снова. Во время обмена данными с вашим веб-сайтом произошла ошибка. У вас нет разрешения на управление плагинами в этом магазине Ошибка при авторизации подключения к Jetpack Ошибка при активации Jetpack - Ошибка при установке Jetpack Подключить Jetpack Перейти в магазин Ошибка Код ошибки %1$s - Теперь ваш магазин <b>%1$s</b> подключён к Jetpack. Подождите, мы подключаем магазин <b>%1$s</b> к Jetpack. Jetpack установлен - Jetpack подключён Выполняется подключение Jetpack - Выполняется установка Jetpack Все готово Подключено Выполняется проверка Подключите магазин к Jetpack Активация + Ошибка при установке Jetpack + Теперь ваш магазин <b>%1$s</b> подключён к Jetpack. + Jetpack подключён + Выполняется установка Jetpack Выполняется установка Jetpack Войдите в <b>%1$s</b>, введя учётные данные магазина, чтобы подключить Jetpack. Войдите в <b>%1$s</b>, введя учётные данные магазина, чтобы установить Jetpack. - Подготовьте учётные данные магазина. + Повторите попытку и обратитесь в службу поддержки, если эта ошибка произойдёт снова. Подключите магазин к Jetpack, чтобы работать с ним в этом приложении. Установите бесплатный плагин Jetpack, чтобы работать с магазином в этом приложении. Создайте онлайн-магазин и начните продажи в кротчайшие сроки. Создайте свой первый магазин + Подготовьте учётные данные магазина. Случайно Никогда Всегда @@ -1414,8 +1450,8 @@ Language: ru Обновить смоделированное устройство чтения карт Подключить Jetpack Подключение магазина - Это место, где люди найдут вас в Интернете. Не беспокойтесь, вы сможете изменить это позднее. Посетители + Это место, где люди найдут вас в Интернете. Не беспокойтесь, вы сможете изменить это позднее. Или войти с помощью пароля Симуляция устройства чтения карт отключена Смоделированный ключ устройства чтения @@ -1444,20 +1480,20 @@ Language: ru Нет доходов за указанный период Доход %1$s — %2$s + Учётная запись с этим адресом эл. почты уже существует. К сожалению, не удалось создать учётную запись с указанными учётными данными. Укажите другой адрес эл. почты. Указанный пароль не соответствует требованиям безопасности. Пароль должен быть более сложным. Пароль слишком короткий. Придумайте пароль, состоящий как минимум из шести символов. Введите допустимый адрес электронной почты. - Учётная запись с этим адресом эл. почты уже существует. Использовать другой адрес Произвольный период Произвольный - Что такое WordPress.com? - Создание учетной записи Выберите пароль Ваш адрес электронной почты + Создание учетной записи Начало работы \nчерез несколько минут Нажимая кнопку «Подключить Jetpack», вы принимаете <a href=\'terms\'>Условия предоставления услуг</a> и разрешаете <a href=\'sync\'>обмен данными</a> с WordPress.com. + Что такое WordPress.com? Включить симуляцию устройства чтения карт Чтобы использовать приложение, получите приглашение у владельца сайта, например у директора магазина или администратора. Подключение к сайту WordPress.com @@ -1474,10 +1510,10 @@ Language: ru На %1$s Невозможно загрузить данные Статистика WooCommerce за сегодня - Статистика магазина за сегодня Аналитика для магазина недоступна Чтобы просмотреть аналитику для магазина, перейдите на последнюю версию WooCommerce. Ваша сеть недоступна.\nПроверьте свои данные или соединение Wi-Fi. Войдите в приложение WooCommerce + Статистика магазина за сегодня Сбой получения данных о подключении… Проверка подключения Jetpack… Не удалось проверить подключение Jetpack. Повторите попытку. @@ -1497,44 +1533,43 @@ Language: ru Недавно на WooCommerce Произошла ошибка, обратитесь в службу поддержки Введите адрес сайта - Получить ссылку на вход по эл. почте Забыли пароль? + Получить ссылку на вход по эл. почте Мы заметили, что вы не закончили настройку очных платежей. <a href=\'\'>Продолжить настройку</a> - Платежи - Понятно! - Теперь можно быстро и просто получать доступ к очным платежам и другим функциям + WC Admin + Войти с помощью адреса магазина + Другие сайты Платежи из вкладки меню + Теперь можно быстро и просто получать доступ к очным платежам и другим функциям + Понятно! + Платежи Ваш адрес электронной почты не используется с учётной записью WordPress.com. - Другие сайты - Войти с помощью адреса магазина - WC Admin - Только что мы отправили специальную ссылку на - Проверьте почту с этого устройства! - Войти с паролем - Вход по специальной ссылке - На вашу электронную почту отправлено письмо со специальной ссылкой. Перейдите по ней, чтобы войти. Войти с учетными данными сайта - Сделайте рекомендации полезными и актуальными: добавьте продукты для дополнительных и сопутствующих продаж. - Добавьте связанные продукты, чтобы повысить продажи - Начните принимать платежи с помощью нашего терминала. Обучение работе с ним займет не больше 20 минут. - Ошибка обновления заказа № %1$d - Заказ № %1$d отмечен как выполненный - Отметить как\nзавершена - Установить WooCommerce - Похоже, %1$s не является сайтом WooCommerce. - Работать с несколькими магазинами - Управлять заказами + На вашу электронную почту отправлено письмо со специальной ссылкой. Перейдите по ней, чтобы войти. + Вход по специальной ссылке + Войти с паролем + Проверьте почту с этого устройства! + Только что мы отправили специальную ссылку на + Настроить + Совет + Что вы планируете делать в приложении WooCommerce? + Просто изучать функционал + Настраивать магазин Создавать и обновлять продукты + Управлять заказами + Работать с несколькими магазинами + Похоже, %1$s не является сайтом WooCommerce. + Установить WooCommerce + Отметить как\nзавершена + Заказ № %1$d отмечен как выполненный + Ошибка обновления заказа № %1$d + Начните принимать платежи с помощью нашего терминала. Обучение работе с ним займет не больше 20 минут. + Добавьте связанные продукты, чтобы повысить продажи + Сделайте рекомендации полезными и актуальными: добавьте продукты для дополнительных и сопутствующих продаж. Смотреть аналитику - Настраивать магазин - Просто изучать функционал - Что вы планируете делать в приложении WooCommerce? - Совет - Настроить Приступим! Войти на WordPress.com Связаться со службой поддержки - Войти с помощью учетной записи WordPress.com Обратитесь за помощью! Возникли проблемы со входом? Артикул @@ -1556,18 +1591,19 @@ Language: ru Простое и быстрое управление. Знаем, что это важно для бизнеса Недавно на WooCommerce + Войти с помощью учетной записи WordPress.com Новый заказ на 50 долл. в магазине WooCommerce Поступил новый заказ! 🎉 сведения Чтобы изменить все %1$s, откройте заказ в разделе администрирования WooCommerce Неполные данные %1$s. Отправить отчёт о состоянии системы - Копировать отчёт о состоянии системы в буфер обмена Продолжить поиск - Оплата при получении, заказ № %1$s для %2$s blog_id %3$s. Изменение платёжного сервиса - Возвращенные средства: %1$s Ожидание платежа + Копировать отчёт о состоянии системы в буфер обмена + Возвращенные средства: %1$s + Оплата при получении, заказ № %1$s для %2$s blog_id %3$s. Продолжить установку Подготовка к установке Установить расширение @@ -1589,19 +1625,18 @@ Language: ru заблокирован Чтобы отредактировать сведения о товарах или оплате, измените статус на \"Ожидание оплаты\". В настоящий момент элементы этого заказа нельзя изменить - Поиск по клиентам Клиенты не найдены + Поиск по клиентам Не сейчас Добавить расширение в магазин - Что такое WooCommerce Shipping? Воспользуйтесь пониженными тарифами на доставку. Пока доступно для служб DHL и USPS, но список расширяется! + Что такое WooCommerce Shipping? Пониженные тарифы Получите заказ, затем просто оплатите доставку, напечатайте этикетку, упакуйте и отправьте. Печатайте с телефона Не нужно гадать, куда делись почтовые марки. Оплачивайте почтовые сборы по мере необходимости Экономьте время и деньги - Выполняйте заказы с помощью WooCommerce Shipping Показать сведения Выбрать вариант %s Исключить товарные категории @@ -1615,7 +1650,6 @@ Language: ru Нет Редактировать товарные категории (%1$d) Выбрать товарные категории - Пока пакетное обновление поддерживается не более чем для 100 вариантов. Превышен лимит пакетного обновления Обновление обычных цен Обновление акционных цен @@ -1625,34 +1659,35 @@ Language: ru Текущие цены отличаются друг от друга Текущая цена: %s Цена для вариантов (%d) будет обновлена - Смешанный - Нет Акционная цена Обычная цена Цена Выберите значение для обновления Пакетное обновление ОК + Выполняйте заказы с помощью WooCommerce Shipping + Пока пакетное обновление поддерживается не более чем для 100 вариантов. Пакетное обновление… - Получение вариантов… + Смешанный + Нет Не удалось найти товарные категории Не удалось загрузить товарные категории Поиск категорий Очистить выбор Нажмите, чтобы снять флажок - Выбрать одну категорию Выбрать категории (%1$d) Товарные категории не найдены Выбрать категории + Нужна транспортная этикетка? + Получение вариантов… + Выбрать одну категорию Скрыть баннер с предложением установить WC Shipping Установить WooCommerce Shipping Печатайте транспортные этикетки с телефона, используя WooCommerce Shipping. - Нужна транспортная этикетка? - Измените количество товара с %1$d на %2$d Обновить обычную цену Обновить акционную цену + Измените количество товара с %1$d на %2$d Расширение WooCommerce Stripe не поддерживается в %1$s - Фильтр Очистить выбор Выбрать %d товар Выбрать товары (%d) @@ -1661,9 +1696,10 @@ Language: ru Изменить товары (%d) Все товары Выбрать товары - Включите это, если купон не следует применять к товарам на распродаже. Купоны на один товар применяются только в том случае, если товар не на распродаже. Купоны на одну покупку применяются только в том случае, если в корзине есть товары не по распродаже. Исключить товары со скидками Включите это, если купон нельзя применять вместе с другими купонами. + Включите это, если купон не следует применять к товарам на распродаже. Купоны на один товар применяются только в том случае, если товар не на распродаже. Купоны на одну покупку применяются только в том случае, если в корзине есть товары не по распродаже. + Фильтр Только для индивидуального использования Лимит пользователя Ограничить использование (до X элем.) @@ -1703,10 +1739,10 @@ Language: ru Не удаётся обновить продукт Произошла ошибка при применении возврата Применение возврата к заказу - Изображение платёжного терминала Вычисленная сумма: %s - Вычислить в процентном соотношении Скопировано в буфер обмена + Изображение платёжного терминала + Вычислить в процентном соотношении Только для клиентов с почтовыми адресами: %1$s Исключает товары со скидками Разрешает бесплатную доставку @@ -1738,12 +1774,12 @@ Language: ru Попробуйте другое средство возврата Возврат отклонён по неизвестной причине Не удалось обработать этот возврат + Копировать Возврат выполнен Обработка возврата Возместить платёж Возврат не выполнен Подготовка к возврату платежа - Копировать Поиск купонов Не удалось создать сообщение для отправки кода купона Ошибка при отправке кода купона. @@ -1768,35 +1804,35 @@ Language: ru Оформление заказа — %s Поделиться ссылкой на оплату Сумма - Сумма - Заказы со скидкой - Эффективность - Максимальный расход %s - Минимальный расход %s - Сводка по купонам Смотреть сводку по купонам - Мы разработали функцию, которая позволяет просматривать и редактировать купоны на вашем устройстве. Просмотр и редактирование купонов Купоны не найдены - %1$s без учёта %2$s - %1$s и %2$s всё Просрочен Активный Купоны Создано %s - %d дн. назад День назад - %d ч. назад Час назад - %d мин. назад Только что Рубрики: %d - %d рубрика \u2022 нет подтверждённых отзывов \u2022 один подтверждённый отзыв - \u2022 подтверждённые отзывы: %d %1$s (%2$s%%) + %d дн. назад + %d ч. назад + %d мин. назад + %d рубрика + \u2022 подтверждённые отзывы: %d + Сумма + Заказы со скидкой + Эффективность + Максимальный расход %s + Минимальный расход %s + Сводка по купонам + Мы разработали функцию, которая позволяет просматривать и редактировать купоны на вашем устройстве. + %1$s без учёта %2$s + %1$s и %2$s Мы работаем над функцией, которая поможет создавать заказы на вашем устройстве! Вы можете попробовать эту функцию, нажав кнопку «+» Зайдите позже, чтобы узнать больше советов и идей по развитию вашего магазина Поздравляем, вы прочитали все примечания! @@ -1805,26 +1841,26 @@ Language: ru Счётчик: %s Купоны Закрыть - Возникла проблема при подключении к сайту. Получен код ошибки HTTP 401. Вызовы XML-RPC на этом сайте заблокированы (код ошибки 401). Если войти не удалось, нажмите на значок справки, чтобы открыть часто задаваемые вопросы. + Возникла проблема при подключении к сайту. Получен код ошибки HTTP 401. Не удалось найти веб-сайт WordPress по этому URL-адресу. Нажмите на значок справки, чтобы открыть часто задаваемые вопросы. Сервисы XML-RPC на этом сайте отключены. Чтобы отправить запрос в службу поддержки, не используйте почту Automattic Мы не поддерживаем счета Stripe, зарегистрированные в %1$s - Расширение WooCommerce Payments не поддерживается в %1$s Нажмите кнопку питания на устройстве чтения Чек отправлен получателю: <strong>%s</strong> Процент (%) + Расширение WooCommerce Payments не поддерживается в %1$s Убрать комиссию из заказа Убрать доставку из заказа Доставка Добавить метод доставки Добавить доставку Имя - Сумма Сборы Информация о клиенте Добавить комиссию + Сумма Изменить примечание клиента Изменить сведения о клиенте Изменить статус заказа @@ -1845,8 +1881,8 @@ Language: ru Очные платежи будут работать только с одним из следующих активированных плагинов. Для продолжения обратитесь к администратору сайта, чтобы деактивировать один из следующих плагинов: Очные платежи будут работать только с одним из следующих активированных плагинов. Для продолжения деактивируйте один из следующих плагинов: Обнаружены конфликтующие плагины оплаты - Общая сумма налогов или + Общая сумма налогов Установить Jetpack В настоящее время очные платежи недоступны Заказ создан @@ -1917,9 +1953,7 @@ Language: ru Добавить другой адрес доставки В наличии %s в наличии - Добавить товары Товары - Добавить сведения о клиенте Клиент Отметить как оплаченный Заказ будет создан и отмечен как оплаченный, если вы получили платеж не через WooCommerce @@ -1927,6 +1961,8 @@ Language: ru Выберите способ оплаты Налоги рассчитываются автоматически на основе адреса магазина Налог (%s%%) + Добавить сведения о клиенте + Добавить товары Получить оплату (%s) Удержать налоги Индивидуальная сумма @@ -1977,21 +2013,21 @@ Language: ru Отсутствует разрешение на поиск устройств поблизости Фильтровать страны Фильтровать округа/области - Округ/область Дата окончания Дата начала Выберите даты Произвольный период Создание заказа с минимумом информации - Платёж без хлопот Создание нового заказа вручную Создать заказ - Создать заказ Введите сумму Получить оплату + Аналитика + Округ/область + Платёж без хлопот + Создать заказ Платёж без хлопот Создавайте заказы на своём устройстве! - Аналитика Все готово Подключение вашего магазина Активация @@ -2038,14 +2074,14 @@ Language: ru Фильтры (%d) Фильтры Период - Статус заказа Выбранный вариант фильтрации Период - Статус заказа Все Показать заказы Отфильтрованные заказы Все заказы + Статус заказа + Статус заказа Расскажите нам больше о %s… Опишите товар для потенциальных покупателей… Серийный номер терминала, скопированный в буфер обмена @@ -2075,8 +2111,8 @@ Language: ru Данные о состоянии системы Теперь вы можете получать платежи с банковских карт через WooCommerce Payments! Принимайте платежи с помощью устройств чтения карт - Количество должно быть не менее %1$s ОК + Количество должно быть не менее %1$s Новое изображение значка функции Переключиться на другой магазин Сбой при обновлении продукта %1$s @@ -2117,10 +2153,10 @@ Language: ru Не удалось автоматически проверить почтовый адрес: %s Не удалось автоматически проверить адрес происхождения. Чтобы убедиться в правильности адреса, найдите его на Google Maps. Мы стараемся упростить процедуру просмотра дополнений к товару с вашего устройства. В настоящее время вы можете просматривать дополнения для своих заказов. Такие дополнения можно создавать и редактировать в веб-консоли. + Сохранить Просмотрите дополнения на своём устройстве! В случае переименования дополнения в веб-консоли следует отметить, что предыдущие заказы больше не будут показывать данное дополнение в приложении. Просмотреть дополнения - Сохранить Загрузить подробности (%d) Не удалось загрузить несколько файлов (%d) Не удалось загрузить %d файл @@ -2139,47 +2175,47 @@ Language: ru Транспортные этикетки приобретены! Напечатать транспортные этикетки Очные платежи - Чтобы полностью зарядить устройство чтения, требуется приблизительно три часа. - Следите за уровнем заряда устройства чтения. - Ваше устройство чтения перейдет в спящий режим через 10 минут неактивности. Чтобы подключить его повторно, просто нажмите кнопку питания. Автоматическое повторное подключение - Для получения платежей просто проведите пальцем, коснитесь экрана или вставьте карту в устройство чтения. - Проведите пальцем, коснитесь экрана или вставьте карту. Поздравляем, теперь вы можете получать платежи по дебетовым и кредитным картам! Устройство чтения подключено Нужна какая-то помощь? <a href=\'\'>Обратиться в службу поддержки</a> <a href=\'\'>Подробнее</a> о приёме платежей с помощью мобильного устройства и заказе устройств чтения карт Очные платежи недоступны в тестовом режиме. Чтобы продолжить, отключите режим. В настоящее время очные платежи недоступны + Чтобы полностью зарядить устройство чтения, требуется приблизительно три часа. + Следите за уровнем заряда устройства чтения. + Ваше устройство чтения перейдет в спящий режим через 10 минут неактивности. Чтобы подключить его повторно, просто нажмите кнопку питания. + Для получения платежей просто проведите пальцем, коснитесь экрана или вставьте карту в устройство чтения. + Проведите пальцем, коснитесь экрана или вставьте карту. Для вашей учётной записи существуют требования на утверждении. Выполните эти требования к %1$s, чтобы продолжать получать очные платежи. Для вашей учётной записи WooCommerce Payments существуют требования на утверждении. Для вашей учётной записи существует по крайней мере одно просроченное требование. Пожалуйста, выполните его, чтобы возобновить очные платежи. В настоящее время очные платежи недоступны Вы сможете получать очные платежи, как только мы завершим проверку вашей учётной записи. - В настоящее время очные платежи недоступны К сожалению, мы не можем поддерживать очные платежи для этого магазина. Перезагрузите после обновления В вашем магазине установлена устаревшая версия расширения WooCommerce Payments. Обновите его, чтобы получать очные платежи. Обновить WooCommerce Payments + В настоящее время очные платежи недоступны Почти готово. Завершите настройку WooCommerce Payments, чтобы начать принимать очные платежи. - Закончите настройку WooCommerce Payments в учётной записи администратора магазина. Обновите после активации - В вашем магазине версия расширения WooCommerce Payments установлена, но не активирована. Активируйте её, чтобы получать очные платежи. Активировать WooCommerce Payments Обновите после установки - Вам будет нужно установить бесплатное расширение WooCommerce Payments в своём магазине, чтобы получать очные платежи. Установить WooCommerce Payments <a href=\'\'>Подробнее</a> о приёме платежей с помощью мобильного устройства и заказе устройств чтения карт Нужна какая-то помощь? <a href=\'\'>Обратиться в службу поддержки</a> - Вы можете по-прежнему принимать очные наличные платежи, если включите способ оплаты \"Оплата при доставке\" в магазине. - Очные платежи по карте не поддерживаются в %1$s - Подключение к вашей учётной записи Очные платежи - Проверьте размеры и вес посылки или выберите другую посылку в разделе сведений о посылках. Тарифы доставки недоступны Все доступные посылки активированы Активация посылки Выберите посылку для активации. + Закончите настройку WooCommerce Payments в учётной записи администратора магазина. + В вашем магазине версия расширения WooCommerce Payments установлена, но не активирована. Активируйте её, чтобы получать очные платежи. + Вам будет нужно установить бесплатное расширение WooCommerce Payments в своём магазине, чтобы получать очные платежи. + Вы можете по-прежнему принимать очные наличные платежи, если включите способ оплаты \"Оплата при доставке\" в магазине. + Подключение к вашей учётной записи + Проверьте размеры и вес посылки или выберите другую посылку в разделе сведений о посылках. + Очные платежи по карте не поддерживаются в %1$s Обязательное поле Закрыть Создан вариант @@ -2188,11 +2224,11 @@ Language: ru Создать вариант Теперь, добавив атрибуты, вы можете создать свой первый вариант. Атрибуты созданы - Выполнено: %1$s%% Не рекомендуется отменять текущее обновление ПО Не удалось выполнить этот платеж Нет подключения к серверу Нет подключения к Интернету + Выполнено: %1$s%% Отправить в оригинальной упаковке Добавить в новую упаковку Эта позиция в настоящее время включена в %s. Куда вы хотите переместить её? @@ -2203,7 +2239,6 @@ Language: ru Не удалось создать упаковку. Повторите попытку. Не удалось создать упаковку: неизвестная проблема с API. Не удалось создать упаковку: %1$s - Пожалуйста, подождите… Создаётся новая упаковка Неверное значение. Обязательное поле @@ -2217,10 +2252,11 @@ Language: ru Коробка Выбрать тип упаковки Тип упаковки - Настройте упаковку, которую вы будете использовать для отправки своих товаров. Мы сохраним её для последующих заказов. Добавить новую упаковку Создать новую упаковку Размеры упаковки должны быть больше нуля. Чтобы продолжить, обновите размеры позиции в разделе \"Доставка\" на странице товара. + Настройте упаковку, которую вы будете использовать для отправки своих товаров. Мы сохраним её для последующих заказов. + Пожалуйста, подождите… Оригинальная упаковка Размеры позиции Индивидуально доставляемая позиция @@ -2233,11 +2269,11 @@ Language: ru Не удалось проверить наличие обновлений ПО <a href=\'\'>Подробнее</a> о приеме мобильных платежей и заказе устройств чтения карт Включить Bluetooth - Не подключено устройство чтения Не удалось подключиться к устройству чтения Подключиться Найдено несколько устройств чтения Заказ уже оплачен + Не подключено устройство чтения Спасибо за покупку! Перейдите по ссылке ниже, чтобы получить чек.\n\n%s Ошибка загрузки таможенной формы Печать таможенного счета-фактуры @@ -2253,12 +2289,11 @@ Language: ru Добавить товар Атрибуты вариантов Включите Bluetooth на мобильном устройстве - Ошибка при загрузке заказа. Состояние заказа в приложении могло устареть. Ваша квитанция от %s Обновление заказа Обновление состояния приложения Ваш клиент выбрал %1$s - Для таможенных форм требуется 10-значный телефонный номер + Ошибка при загрузке заказа. Состояние заказа в приложении могло устареть. Таможенная форма заполнена При наличии проблем с печатью с устройства обратитесь в службу поддержки вашего принтера. Если печать недоступна, можно всегда сохранить квитанцию в формате PDF и отправить её по электронной почте, чтобы распечатать с другого устройства. @@ -2271,6 +2306,7 @@ Language: ru Чтобы создать вариант, необходимо сначала задать атрибуты (например, «Цвет» или «Размер»). 1 вариант Вариантов: %1$s + Для таможенных форм требуется 10-значный телефонный номер Отслеживание USPS Обновление ПО устройства чтения Обновление ПО @@ -2280,7 +2316,6 @@ Language: ru Чтобы принимать платежи, обновите ПО устройства чтения Обновить ПО устройства чтения Заряд %s%% - ПОДКЛЮЧЁННОЕ УСТРОЙСТВО ЧТЕНИЯ Подключение устройства чтения карт Включите устройство чтения и расположите его рядом с мобильным устройством Убедитесь, что устройство чтения заряжено @@ -2309,12 +2344,10 @@ Language: ru Атрибутика Страна производства или сборки товара Страна происхождения - Тарифный код должен включать шесть цифр Тарифный код HS (необязательно) Описание Содержимое посылки Необходимо указать номер ITN для посылок в %1$s. - Номер ITN необходимо указывать для посылок стоимостью более 2500 долл. США за тарифный код Недопустимый формат Сведения об ограничениях Сведения о содержимом @@ -2322,17 +2355,20 @@ Language: ru Тип содержимого Вернуть отправителю в случае невозможности доставки до %s + ПОДКЛЮЧЁННОЕ УСТРОЙСТВО ЧТЕНИЯ + Тарифный код должен включать шесть цифр + Номер ITN необходимо указывать для посылок стоимостью более 2500 долл. США за тарифный код Если вы включите этот параметр, клиент получит эл. письмо с подтверждением, когда заказ будет выполнен Просмотр заказа - Заказ 🎉 завершён! - Проверка роли… Неверная роль пользователя Подробнее о ролях и разрешениях Это приложение поддерживает только роли администратора и менеджера магазина. Свяжитесь с владельцем магазина для изменения роли. Добавляйте новые товары и редактируйте существующие откуда угодно + Пропустить + Заказ 🎉 завершён! + Проверка роли… Управляйте заказами и редактируйте их на ходу Отслеживайте продажи и узнавайте, какие товары пользуются спросом - Пропустить Внешний товар Сгруппированный товар Вариативный товар @@ -2341,9 +2377,6 @@ Language: ru Простой физический товар Открыть настройки Открыть настройки - Bluetooth отключен - Определение местоположения отключено - Отсутствует разрешение на определение точного местоположения Не удалось подключиться к устройству чтения. Подключение к устройству чтения Подключиться к устройству чтения @@ -2351,9 +2384,10 @@ Language: ru Поиск устройств чтения Количество позиций Создать новую транспортную этикетку - Простой виртуальный продукт + Bluetooth отключен + Определение местоположения отключено + Отсутствует разрешение на определение точного местоположения Хотите удалить этот вариант? - Создание варианта Удаление продукта Отправить квитанцию Печать квитанции @@ -2367,14 +2401,16 @@ Language: ru Не удалось просмотреть транспортную этикетку. Установите приложение для просмотра PDF-файлов и повторите попытку. Мы не смогли найти сайт WordPress по указанному вами адресу. Убедитесь, что WordPress установлен, и что вы используете самую последнюю версию. несколько строк данных доставки + Простой виртуальный продукт + Создание варианта Не удалось отметить заказ как выполненный Возникла ошибка при покупке этикеток Пожалуйста, подождите… Покупка этикеток - Изображения этикеток сроком более 180 дней удаляются нашими технологическими партнерами в целях обеспечения общей безопасности и конфиденциальности данных. Напечатать транспортную этикетку Сохранить для последующего использования Транспортная этикетка приобретена! + Изображения этикеток сроком более 180 дней удаляются нашими технологическими партнерами в целях обеспечения общей безопасности и конфиденциальности данных. Возврат стоимости этикеток со сроком более 30 дней не производится. Тип Переименовать @@ -2395,18 +2431,17 @@ Language: ru Только владелец сайта может управлять способами оплаты транспортных этикеток. Чтобы управлять способами оплаты, свяжитесь с владельцем магазина %1$s (%2$s). Добавить варианты Добавить вариант - Создайте первый вариант Итого %s Выбрано %s ставок Подходит для бесплатной подписи Подходит для бесплатного самовывоза - Страхование (%s) - отслеживание Включает %s Требуется подпись совершеннолетнего лица (%s) Требуется подпись (%s) + Страхование (%s) + отслеживание Клиент оплатил %1$s из %2$s за доставку. - При покупке транспортных этикеток через WooCommerce вы сэкономите от 5 до 40 % по сравнению с тарифами почты. + Создайте первый вариант Что такое скидка WooCommerce Services? При загрузке вариантов доставки произошла ошибка. Перевозчики и тарифы @@ -2424,6 +2459,7 @@ Language: ru Укажите имя каждой опции и нажмите клавишу Enter или коснитесь существующей опции. Название опции + При покупке транспортных этикеток через WooCommerce вы сэкономите от 5 до 40 % по сравнению с тарифами почты. Ошибка при сохранении настроек Пожалуйста, подождите… Сохранение настроек @@ -2446,18 +2482,15 @@ Language: ru Добавить атрибут Атрибуты Редактировать атрибуты - Общий вес посылок: %1$s %2$s Число товаров в посылках (%2$d): %1$d Общий вес посылок: %1$s %2$s Специальные посылки Не удаётся получить данные о товарах - Некоторые обязательные поля не заполнены. Неверный вес Выбранная посылка Пожалуйста, подождите… Загрузка посылок! Посылка %1$d - %d элементов Не удаётся загрузить определения посылок Включает вес посылок Общий вес посылок (%1$s) @@ -2470,16 +2503,17 @@ Language: ru Мы немного изменили введённый адрес. Если всё правильно, используйте предложенный адрес для доставки по назначению. Редактировать выбранный адрес Использовать выбранный адрес + Некоторые обязательные поля не заполнены. + Общий вес посылок: %1$s %2$s + %d элементов Загрузка адреса Доступны новые функции! - Найти на карте Связаться с клиентом Недопустимая улица Не указан номер дома Адрес не найден Не удалось автоматически проверить почтовый адрес. Укажите его на Google Картах или свяжитесь с клиентом и убедитесь, что адрес указан верно. Сбой проверки адреса - Пожалуйста, подождите… Выполняется проверка адреса Не удалось загрузить данные адреса Использовать введённый адрес @@ -2490,6 +2524,8 @@ Language: ru Телефон Компания Имя + Пожалуйста, подождите… + Найти на карте Приложение \"Google Карты\" найдено Пожалуйста, подождите… Удаление изображений вариантов продуктов поддерживается в версии WooCommerce 4.7 и более поздних. @@ -2505,31 +2541,30 @@ Language: ru Сведения об упаковке Создание почтового бланка Узнать больше - Сократите очередь на почте, распечатывая транспортные этикетки дома с мобильного устройства со скидкой! Экономьте время и деньги, выполняя заказы с помощью WooCommerce Shipping WooCommerce Shipping Отметить заказ как выполненный - Узнать больше о распечатке этикеток с вашего мобильного устройства Создание почтового бланка - Теперь вы можете создавать транспортные этикетки для всех физических заказов прямо со своего устройства с помощью бесплатного плагина WooCommerce Shipping. Нажмите \"Создать транспортную этикету\", чтобы попробовать новую бета-функцию! Создавайте транспортные этикетки со своего устройства! + Теперь вы можете создавать транспортные этикетки для всех физических заказов прямо со своего устройства с помощью бесплатного плагина WooCommerce Shipping. Нажмите \"Создать транспортную этикету\", чтобы попробовать новую бета-функцию! + Сократите очередь на почте, распечатывая транспортные этикетки дома с мобильного устройства со скидкой! + Узнать больше о распечатке этикеток с вашего мобильного устройства + Правка Сборы Чистая выплата Платно Дополнительные сведения о подключении Jetpack - Правка Подтвердить Перетащите фотографии, чтобы изменить их порядок + Удалить Настройки загрузки Введите правильное имя Введите URL-адрес файла - Библиотека файлов WordPress Убедитесь, что введен допустимый URL-адрес Пожалуйста, подождите… Загрузка файлов Ошибка загрузки файлов Добавьте скачиваемый файл - Добавьте скачиваемый файл из Добавлять к покупкам скачиваемый файл Отмена Да, изменить @@ -2538,7 +2573,6 @@ Language: ru Файл Удалить файл? Загружаемый товар - Удалить Срок действия для загрузок Лимит загрузок Введите количество дней, по окончанию которых ссылка на скачивание перестанет работать, или оставьте пустым, если срок действия не указан @@ -2553,11 +2587,13 @@ Language: ru Возможно, нужно <b>настроить печать по Wi-Fi на самом принтере</b>. Убедитесь, что микропрограммное обеспечение принтера обновлено, и ознакомьтесь с документацией принтера. Можно выбрать для принтера <b>службу печати по умолчанию</b> или установить <b>приложение от производителя принтера</b> (здесь должен появиться рекомендованный вариант). Убедитесь, что ваши принтер и устройство подключены к <b>одной сети Wi-Fi</b> - Оцените новую простую процедуру создания связанных и сгруппированных продуктов, которая готова к запуску + Добавьте скачиваемый файл из + Библиотека файлов WordPress Увеличивайте продажи благодаря продаже дополнительных и связанных продуктов Изменить товары Добавить товары Продукты, которые будут предложены пользователю в дополнение к выбранному продукту в корзине + Оцените новую простую процедуру создания связанных и сгруппированных продуктов, которая готова к запуску Кросселы Продукты, которые будут предложены пользователю вместо просматриваемого в настоящий момент продукта (например, более прибыльные продукты) Апсейл @@ -2565,7 +2601,6 @@ Language: ru %1$s%2$s x %3$s Получить ссылку для входа по email Не получается найти учётную запись WordPress.com для этого адреса email. - Протестируйте наши дополнительные модули заказов в процессе подготовки к запуску Создание продуктов Параметры Не удалось отправить продукт в корзину @@ -2577,24 +2612,25 @@ Language: ru Добавление опций, например размера и цвета, сейчас возможно только в Интернете. Эти варианты будут показаны на странице продукта на вашем сайте. Создавайте продукты в приложении! Продукт не найден - Если вам по-прежнему не удается выполнить печать со своего устройства, вы можете <b>сохранить этикетку в формате PDF</b> и отправить ее по эл. почте, чтобы распечатать с другого устройства. - Нажав <b>«Напечатать транспортную этикетку»</b>, можно выбрать и добавить принтер, если ранее вы не выполняли печать с этого устройства. Варианты формата этикетки - Печать с устройства Этикетка (4 x 6 in) Letter (8,5 x 11 in) Legal (8,5 x 14 in) Не удалось выполнить предварительный просмотр транспортной этикетки - Не знаете, как печатать с помощью мобильного устройства? См. макет этикетки и варианты размера бумаги Напечатать транспортную этикетку Выбрать размер бумаги Размер бумаги - Если вы уже использовали этикетку в посылке, ее распечатка и повторное использование является нарушением наших условий предоставления услуг. Если при печати купленной этикетки произошла ошибка, можно распечатать ее еще раз. Мы стараемся упростить процедуру печати этикеток с устройства. Сейчас, если вы создали этикетки для этого заказа в разделе администрирования магазина с помощью WooCommerce Shipping, их можно распечатать из описания заказа (здесь). Печатайте транспортные этикетки со своего устройства! + Печать с устройства + Если вы уже использовали этикетку в посылке, ее распечатка и повторное использование является нарушением наших условий предоставления услуг. + Если вам по-прежнему не удается выполнить печать со своего устройства, вы можете <b>сохранить этикетку в формате PDF</b> и отправить ее по эл. почте, чтобы распечатать с другого устройства. + Нажав <b>«Напечатать транспортную этикетку»</b>, можно выбрать и добавить принтер, если ранее вы не выполняли печать с этого устройства. Напечатать транспортную этикетку + Протестируйте наши дополнительные модули заказов в процессе подготовки к запуску + Не знаете, как печатать с помощью мобильного устройства? \u0022%1$s\u0022 Черновик товара сохранен Ошибка сохранения черновика товара @@ -2642,12 +2678,12 @@ Language: ru Войдите с помощью другой учетной записи Выберите магазин для подключения Продолжить с WordPress.com - Товар с вариантами исполнения, например по цвету или размеру %d товар выбран %d тов. выбрано Добавление товаров в группу Добавить товар Введите пароль + Товар с вариантами исполнения, например по цвету или размеру Назад в магазин Свяжитесь с нами Обратите внимание, что это не заявка в службу поддержки и мы не сможем ответить на ваш отзыв.\n\nНужна какая-то помощь? %1$s @@ -2682,24 +2718,24 @@ Language: ru При добавлении метки произошла ошибка Добавление метки Запрос на возврат средств обрабатывается. Пожалуйста, подождите… - Запрос на возврат средств отправлен Вернуть оплату почтового бланка (-%1$s) Сумма, доступная для возврата Дата покупки - Вы можете запросить возврат средств за неиспользованный почтовый бланк Обработка займет от 14 дней. Запросить возврат средств Вернуть средства за почтовый бланк + Вы можете запросить возврат средств за неиспользованный почтовый бланк Обработка займет от 14 дней. + Запрос на возврат средств отправлен Физический Краткое описание товара Используйте метки, чтобы товары было проще искать Объедините продукты в группы + Отключено Добавить вес и размеры Добавить другие сведения Организуйте свои товары с помощью меток Добавьте первую метку Метки Добавить метку - Отключено Виртуальный товар Добавить другие сведения %1$s товар @@ -2707,9 +2743,7 @@ Language: ru %s товар Оставшиеся товары %1$s \u2022 %2$s - Запрошен возврат оплаты транспортной этикетки %1$s Отследить посылку - %1$s\n%2$s Скрыть сведения о доставке Показать сведения о доставке Банковская карта @@ -2719,6 +2753,8 @@ Language: ru Доставка в Доставка из Посылка %d + %1$s\n%2$s + Запрошен возврат оплаты транспортной этикетки %1$s Артикул: %1$s %1$s (%2$s пар.) Транспортные этикетки @@ -2739,8 +2775,8 @@ Language: ru Заявление о защите конфиденциальности для пользователей из Калифорнии Сохранить изменения До %1$s - Появилось больше возможностей редактирования товаров. Теперь можно изменять изображения, пользоваться предварительным просмотром и делиться товарами. Доступны новые опции редактирования + Появилось больше возможностей редактирования товаров. Теперь можно изменять изображения, пользоваться предварительным просмотром и делиться товарами. Доступны ограниченные возможности редактирования Товары %1$s x %2$s @@ -2834,11 +2870,11 @@ Language: ru Ширина Длина Продукты, по которым возвращены средства - %1$s (%2$s x %3$d) %1$s с помощью %2$s Вы уверены, что хотите вернуть деньги? Это действие нельзя отменить. Продукты, по которым возвращены средства Возврат оплаты + %1$s (%2$s x %3$d) Подписаться на WordPress.com К сожалению, результаты по запросу \"%s\" не найдены Получайте высококачественные отзывы о продуктах в вашем магазине @@ -2859,33 +2895,32 @@ Language: ru Добавить запасы Просмотр информации о ваших заказах… Введите текст - Введите название товара - Товар сохранён Ошибка обновления продукта Пожалуйста, подождите… Опишите продукт Описание Редактировать описание + Введите название товара + Товар сохранён + Готово Отменить изменения? Обновить - Готово Идет возврат средств, подождите… Верните средства за доставку Выбрать количество Возврат средств за доставку Возврат средств за продукты - %1$s x %2$s каждый Выбрано элементов: %d Ничего не выбирать Выбрать все Ожидается подтверждение возврата средств… + %1$s x %2$s каждый Изменять размер и сжимать изображения для ускорения загрузки Оптимизация изображений Сделать фото Выбрать с устройства Выберите способ загрузки Загрузки - Загрузка изображений…%1$d из %2$d Загрузка изображения… Нет доступа к камере Вы уверены, что хотите удалить это изображение? @@ -2900,6 +2935,7 @@ Language: ru Добавить изображение Ближайшие Удалить + Загрузка изображений…%1$d из %2$d Не удалось получить доступ к вашему сайту. Возможно, потребуется обратиться в техподдержку службы хостинга, чтобы решить эту проблему. Не удалось получить доступ к вашему сайту: возникла проблема с <b>сертификатом SSL</b>. Возможно, потребуется обратиться в техподдержку службы хостинга, чтобы решить эту проблему. Не удалось получить доступ к вашему сайту: необходимо выполнить <b>проверку подлинности HTTP</b>. Возможно, потребуется обратиться в техподдержку службы хостинга, чтобы решить эту проблему. @@ -2908,8 +2944,8 @@ Language: ru Войдите с именем пользователя и паролем для сайта. Войдите с именем пользователя и паролем для сайта %1$s Отправить письмо с подтверждением - Оцените новые возможности редактирования, пока мы готовим их к запуску Редактирование продукта + Оцените новые возможности редактирования, пока мы готовим их к запуску При загрузке вашей учетной записи произошла ошибка. Повторите попытку сейчас или закройте и попробуйте позже. Произошла ошибка. Войдите, чтобы продолжить. Подключение к сайту… @@ -2944,12 +2980,12 @@ Language: ru Нет соответствующих товаров В этом списке пока нет товаров %s в наличии - В наличии \u2022 %d вар. Изображение продукта Пользователь %1$s оставил отзыв на %2$s Не одобрен Ошибка при получении нового отзыва о товаре Ошибка при получении отзывов о товарах + В наличии \u2022 %d вар. В процессе возврата что-то пошло не так. Повторите попытку. Средства возвращены заказчику. Запрос на возврат средств за %s обрабатывается. Пожалуйста, подождите… @@ -2983,12 +3019,12 @@ Language: ru Статистика за сегодня Войти Уже есть Jetpack? %1$s - Попытка входа через Jetpack… обновите приложение, чтобы продолжить - Чтобы использовать это приложение для %1$s, настройте плагин Jetpack и подключите его к этой учетной записи. \n\nПосле настройки перезагрузите приложение Попробуйте другой магазин База данных переведена на более раннюю версию, идет повторное создание таблиц и загрузка магазинов Загрузка магазинов + Попытка входа через Jetpack… + Чтобы использовать это приложение для %1$s, настройте плагин Jetpack и подключите его к этой учетной записи. \n\nПосле настройки перезагрузите приложение Перевозчики не найдены Введите адрес сайта полностью, например example.com. Нет обзоров! @@ -2999,12 +3035,11 @@ Language: ru Не удалось получить параметры: некоторые API недоступны для этой пары идентификатора приложения OAuth и учетной записи. Есть вакансии! Копировать номер отслеживания - Поиск WooCommerce… обновите приложение + Поиск WooCommerce… Адрес не указан Не можете вспомнить адрес эл. почты, указанный при регистрации? Расположенный по этому адресу веб-сайт не имеет отношения к платформе WordPress. Чтобы подключиться к нему, необходимо установить WordPress. - Войдите на WordPress.com, чтобы подключиться к <b>%1$s</b> Зимбабве Замбия Йемен @@ -3141,6 +3176,7 @@ Language: ru Ямайка Кот-д\'Ивуар Италия + Войдите на WordPress.com, чтобы подключиться к <b>%1$s</b> Израиль Остров Мэн Ирландия @@ -3247,24 +3283,15 @@ Language: ru Афганистан Аландские острова Обзор - Другой перевозчик Другая - Пожалуйста, введите название компании-перевозчика Введите номер отслеживания - Пожалуйста, выберите перевозчика Отменить отслеживание? Не удалось добавить отслеживание Отслеживание посылки добавлено - Ошибка получения данных о перевозчиках - Выбранный перевозчик - Перевозчики Дата отправки Введите ссылку на отслеживание - Введите название компании-перевозчика Введите номер отслеживания - Выберите перевозчика Ссылка на отслеживание (не обязательно) - Название компании-перевозчика Номер отслеживания Компания-перевозчик Добавить отслеживание @@ -3277,19 +3304,25 @@ Language: ru Отследить посылку Чтобы узнать, какой адрес эл. почты вы использовали для подключения к WordPress.com, в режиме управления сайтом в %1$sконсоли Jetpack%2$s перейдите в %3$sПодключения > Подключение учетных записей%4$s Какой адрес эл. почты я использую для входа? - Не можете вспомнить адрес электронной почты? Jetpack — это бесплатный плагин WordPress с дополнительными инструментами, которые обеспечивают удобное управление магазином с мобильных устройств и доступ к расширенным возможностям, например push-уведомлениям и статистике. Что такое Jetpack? Открыть список подключенных магазинов - Похоже, что %1$s подключён к другой учётной записи WordPress.com. Продолжить редактирование + Другой перевозчик + Пожалуйста, введите название компании-перевозчика + Пожалуйста, выберите перевозчика + Ошибка получения данных о перевозчиках + Выбранный перевозчик + Перевозчики + Введите название компании-перевозчика + Выберите перевозчика + Название компании-перевозчика + Похоже, что %1$s подключён к другой учётной записи WordPress.com. + Не можете вспомнить адрес электронной почты? Please log in with your username and password. Войдите, используя имя пользователя WordPress.com вместо адреса электронной почты. The site at this address is not a WordPress site. For us to connect to it, the site must use WordPress. Help Center - Виртуальный - Сборный - С вариантами Allow, but notify customer Разрешить Do not allow @@ -3297,6 +3330,9 @@ Language: ru Out of stock In stock Читать далее + Сборный + С вариантами + Виртуальный Не удалось загрузить изображение Черновик Личный @@ -3342,11 +3378,11 @@ Language: ru Попробовать Понятно Нажмите, чтобы переключиться между магазинами - Выбрать магазин Выйти Изменить статус заказа Нажмите, чтобы изменить статус заказа Применить + Выбрать магазин Нет, спасибо Позже Оценить сейчас @@ -3384,15 +3420,15 @@ Language: ru Оповещения об обзоре товаров Оповещения о новом заказе Заказчику - Проверка сайта… Инструкции по обновлению Поиск + Проверка сайта… Обновить и еще %d. Новых уведомлений: %d - Версия %s Условия предоставления услуг WooCommerce для Android + Версия %s Имя Лицензии на ПО с открытым исходным кодом О приложении @@ -3418,9 +3454,9 @@ Language: ru Отчёты об отказах Поделиться Версия %s - Пароль для HTTP-авторизации - Имя для HTTP-авторизации - Требуется авторизация + Слишком много попыток отправить СМС-код проверки, отдохните и запросите снова через пару минут. + Ни одна учетная запись WordPress.com не совпадает с этой записью в Google. + Войдите в учетную запись WordPress.com, с которой был подключен Jetpack. Магическая ссылка отослана Email регистрация Проверка кода @@ -3429,32 +3465,9 @@ Language: ru Вход по магической ссылке Вход по адресу сайта Вход по email адресу - Произошла ошибка - Пожалуйста, введите код авторизации для продолжения. - Пожалуйста, перепроверьте свой пароль для продолжения. - Вход остановлен - Пожалуйста подождите пока авторизуемся. - Вход … - Нажмите чтобы продолжить. - Вход успешен! - Возникла ошибка сети. Проверьте ваше подключение и попробуйте снова. - Укажите сайт WordPress.com или автономный сайт с подключённым модулем Jetpack - Не удалось подключиться. При попытке подключиться к конечной точке XMLRPC вашего сайта мы получили\n ошибку 403. Это необходимо для обмена данными между приложением и вашим сайтом. Свяжитесь с хостинг-провайдером, чтобы решить\n эту проблему. - Не удалось подключиться. Ваш хостинг-провайдер блокирует запросы POST, которые нужны приложению\n для обмена данными с вашим сайтом. Свяжитесь с хостинг-провайдером, чтобы решить эту проблему. - Не удалось подключиться. На сервере отсутствуют необходимые методы XML-RPC. - Убедитесь, что введен допустимый URL-адрес сайта - Произошла ошибка - Забыли пароль? - Введите правильный email адрес - Проверка адреса эл. почты - Войдите заново для продолжения. - Войдите в учетную запись WordPress.com, с которой был подключен Jetpack. - Не удалось загрузить профиль. - Обнаружена копия сайта. - Этот сайт уже существует в приложении, его нельзя добавить. - Имя пользователя или пароль введены неверно - Google отвечает слишком долго. Возможно вам стоит подождать пока ваше подключение к Интернет станет лучше. + Еще нет учетной записи? %1$sЗарегистрируйтесь%2$s Регистрация через Google… + Google отвечает слишком долго. Возможно вам стоит подождать пока ваше подключение к Интернет станет лучше. Зарегистрироваться через Google Зарегистрироваться с адресом Email Регистрируясь, вы соглашаетесь с нашими %1$sПравилами пользования%2$s. @@ -3464,20 +3477,54 @@ Language: ru Возникла проблема при отправке почты. Вы можете повторить сейчас или закрыть и попробовать еще раз позже. Для создания новой учетной записи WordPress.com, пожалуйста введите ваш адрес email. Возникла ошибка проверки адреса email. - \nВозможно попробуете другую учетную запись? + Произошла ошибка + Пожалуйста, введите код авторизации для продолжения. + Пожалуйста, перепроверьте свой пароль для продолжения. + Вход остановлен + Пожалуйста подождите пока авторизуемся. + Вход … + Нажмите чтобы продолжить. + Вход успешен! Процесс входа в Google не может быть запущен. - Слишком много попыток отправить СМС-код проверки, отдохните и запросите снова через пару минут. + Пожалуйста, введите пароль + \nВозможно попробуете другую учетную запись? Возникла ошибка подключения к учетной записи Google. - Ни одна учетная запись WordPress.com не совпадает с этой записью в Google. Закрыть Войти через Google. + Возникла ошибка сети. Проверьте ваше подключение и попробуйте снова. Вы вошли как Не удалось определить ваш почтовый клиент - Еще нет учетной записи? %1$sЗарегистрируйтесь%2$s Введите проверочный код. - Пожалуйста, введите пароль - Введите имя пользователя + Обнаружена копия сайта. + Этот сайт уже существует в приложении, его нельзя добавить. + Не удалось подключиться. При попытке подключиться к конечной точке XMLRPC вашего сайта мы получили\n ошибку 403. Это необходимо для обмена данными между приложением и вашим сайтом. Свяжитесь с хостинг-провайдером, чтобы решить\n эту проблему. + Не удалось подключиться. Ваш хостинг-провайдер блокирует запросы POST, которые нужны приложению\n для обмена данными с вашим сайтом. Свяжитесь с хостинг-провайдером, чтобы решить эту проблему. + Проверка адреса эл. почты + Не удалось подключиться. На сервере отсутствуют необходимые методы XML-RPC. + Не удалось загрузить профиль. + Войдите заново для продолжения. + Забыли пароль? + Имя пользователя или пароль введены неверно + Введите правильный email адрес + Произошла ошибка + Требуется авторизация + Убедитесь, что введен допустимый URL-адрес сайта + Пароль для HTTP-авторизации + Имя для HTTP-авторизации + Укажите сайт WordPress.com или автономный сайт с подключённым модулем Jetpack + Альтернативно: + Общее + \@%s + Войти с именем пользователя. + Войти с адресом вашего сайта. + Пришлите мне другой код. + Мы послали текстовое сообщение на телефонный номер оканчивающийся на %s. Пожалуйста введите проверочный код из SMS. + Чтобы войти через эту учетную запись Google, пожалуйста укажите соответствующий пароль WordPress.com. Это запрашивается только один раз. Войдите в WordPress.com чтобы поделиться содержимым. + Введите адрес вашего сайта WordPress, на который вы хотите поделиться содержимым. + Ошибка при открытии веб-браузера по умолчанию. Выберите другое приложение: + Не удаётся открыть ссылку + Введите имя пользователя Чтобы получить доступ к записи, войдите на WordPress.com. При добавлении сайта произошла ошибка. Код ошибки: %s Проверка адреса сайта @@ -3486,25 +3533,15 @@ Language: ru Какой адрес у моего сайта? Как найти адрес своего сайта? Адрес сайта - Введите адрес вашего сайта WordPress, на который вы хотите поделиться содержимым. \@%s Вы уже вошли на WordPress.com Продолжить - Подключить сайт Подключить ещё один сайт - Чтобы войти через эту учетную запись Google, пожалуйста укажите соответствующий пароль WordPress.com. Это запрашивается только один раз. Введите свой пароль на WordPress.com. - В настоящий момент ссылка недоступна. Введите пароль Выполняется запрос электронного письма со ссылкой для входа Похоже, пароль введён неправильно. Проверьте правильность введенных данных и повторите попытку. Выполняется запрос на получение проверочного кода в SMS-сообщении. - Пришлите мне другой код. Пришлите мне сообщение с кодом. - Мы послали текстовое сообщение на телефонный номер оканчивающийся на %s. Пожалуйста введите проверочный код из SMS. - Почти готово! Введите проверочный код для WordPress.com из приложения Authenticator. - Войти с именем пользователя. - Войти с адресом вашего сайта. - Альтернативно: Открыть почту Вперед Управляйте сайтом, созданным с помощью Jetpack, где угодно — WordPress можно всегда носить с собой. @@ -3512,29 +3549,39 @@ Language: ru Следите за обновлениями любимых сайтов и присоединяйтесь к беседе в любом месте и в любое время. Наблюдайте, как пользователи со всего света читают ваш сайт и общаются на нем в реальном времени. Публикуйте записи, гуляя в парке. Ведите блог из автобуса. Отправляйте комментарии из-за столика в кафе. WordPress можно брать с собой повсюду! - Войти - Помощь - Пароль - Имя - Введите пароль. + Вы уже вошли в учетную запись WordPress.com. Вы не можете добавить сайт WordPress.com, привязанный к другой учетной записи. + Повторить попытку + Выйти Отправить ссылку + В настоящий момент ссылка недоступна. Введите пароль + Вход в систему + Введите пароль. + Адрес электронной почты + Подробнее + Назад Неверный код подтверждения Код подтверждения - Адрес электронной почты + Помощь + Отменить + Войти + Имя + Пароль + Без заголовка + Настройки + Сегодня + Отмена Поддержка WooCommerce для Android %s флажок не установлен флажок установлен Политика сторонней организации Политика использования файлов cookie Политика конфиденциальности - Сделано с любовью компанией Automattic. %1$s Мы используем и другие средства сбора информации, в том числе средства сторонних разработчиков. Ознакомьтесь с этими средствами и способами управления ими. Ознакомьтесь с политикой конфиденциальности Эти сведения помогают нам улучшать продукты, предлагать более полезную рекламу, настраивать WooCommerce согласно вашим предпочтениям и решать другие задачи. Дополнительную информацию см. в политике конфиденциальности Отправлять информацию об использовании сервисов во время работы в учётной записи WordPress в службу аналитики Собирать информацию Настройки конфиденциальности - Настройки Статус заказа Средства возвращены Отменён @@ -3548,7 +3595,6 @@ Language: ru Добавить Отправить примечание клиенту по электронной почте Ошибка при изменении заказа - Ошибка при получении примечаний Заказ отмечен как выполненный Отметить заказ как выполненный Добавить примечание к заказу @@ -3557,7 +3603,6 @@ Language: ru Показать платёжные сведения Платёж погашен Примечания к заказу - Личный Составить примечание к заказу Изображение профиля клиента Примечание клиента @@ -3571,7 +3616,6 @@ Language: ru отправить клиенту эл. письмо Платёжные сведения Сведения о доставке - Заказ №%s %1$s %2$s Информация о клиенте Фильтр @@ -3582,8 +3626,6 @@ Language: ru Заказов нет Просмотреть заказы Просмотреть заказ - Нет активности за этот период - Всего заказов: %s Изображение ошибки Ошибка при получении данных Доход @@ -3597,55 +3639,50 @@ Language: ru Нет магазинов WooCommerce Фотография в вашем профиле Подключенный магазин - Ознакомьтесь с %1$sинструкциями по настройке%2$s. Для подключения к вашему магазину этому приложению требуется Jetpack. - \@%s Введите адрес магазина WooCommerce, к которому требуется подключиться. Для управления магазинами WooCommerce выполните вход, указав адрес электронной почты своей учётной записи WordPress.com. - Вы уже вошли в учетную запись WordPress.com. Вы не можете добавить сайт WordPress.com, привязанный к другой учетной записи. - Не удаётся открыть ссылку Не найдено приложение для отправки SMS Не найдено приложение для отправки электронных писем Не найдено приложение для звонков - Ошибка при открытии веб-браузера по умолчанию. Выберите другое приложение: Не удаётся открыть ссылку - %1$s в %2$s Больше месяца назад Больше недели назад Больше двух дней назад Вчера Сегодня Товары - Отменить В этом году В этом месяце На этой неделе - Сегодня Товар Ваша сеть недоступна. Проверьте свои данные или соединение Wi-Fi. Не в сети u2014, используются кэшированные данные Подробнее - Отмена - Без заголовка Продолжить - Назад - Повторить попытку Скрыть подробности - Подробнее Скидка Подытог Налоги Оплата Доставка + Итого -%1$s%2$s %1$s%2$s Заказы Мой магазин - Выйти - Вход в систему Все - Общее WooCommerce + %1$s в %2$s + Заказ №%s + Сделано с любовью компанией Automattic. %1$s + Личный + Подключить сайт + Нет активности за этот период + Всего заказов: %s + Ошибка при получении примечаний + Ознакомьтесь с %1$sинструкциями по настройке%2$s. + Почти готово! Введите проверочный код для WordPress.com из приложения Authenticator. @string/date_timeframe_custom @string/date_timeframe_today diff --git a/WooCommerce/src/main/res/values-sv/strings.xml b/WooCommerce/src/main/res/values-sv/strings.xml index 0dfdf840efb..3baa4d86e5e 100644 --- a/WooCommerce/src/main/res/values-sv/strings.xml +++ b/WooCommerce/src/main/res/values-sv/strings.xml @@ -1,11 +1,47 @@ + Kuvert + Låda + Lägg till paket + Spara detta som en ny paketmall + Höjd + Bredd + Längd + Pakettyp + Sparad + Schemalägg upphämtning + Spåra leverans + Lär dig hur man skriver ut från din mobila enhet + Begär återbetalning + Fraktbolag + Anpassat + Obs: Återanvändning av en utskriven fraktetikett är ett brott mot våra användarvillkor och kan leda till åtal. + Härifrån kan du skriva ut fraktetiketten igen eller ändra storlek på fraktetiketten. + Din fraktetikett är klar att skrivas ut. + Du kan bara redigera den här beställningen på webben, eftersom den använder %1$s och din webbplats valuta är %2$s + Snabbast + Billigast + Frakttjänst + Köp etikett + Köp etikett · %1$s + Välj ett paket + Beställningsdetaljer + Markera denna beställning som slutförd och avisera kunden + Fraktkostnad + Försändelseinformation + Ange paketets mått eller välj ett paketalternativ från transportören för att se tillgängliga fraktavgifter. + Välj ett paket för att få fraktavgifter + Skickar du farliga artiklar eller farligt material? + %1$s  ·  %2$s + Minimera/maximera artikelkortet + Nej + Sorterad efter 1%s Spara mitt val för framtida kampanjer <b>Bra för:</b> %s Välj mål %s @@ -20,11 +56,11 @@ Language: sv_SE 4. Din kund trycker sitt kort mot baksidan av din telefon. HTML Text + Anpassade fält + Visa och redigera anpassade fält + Visa och redigera anpassade fält Växla mellan text- och HTML-redigerare När ändringar av anpassade fält sparas träder de i kraft omedelbart. - Visa och redigera anpassade fält - Visa och redigera anpassade fält - Anpassade fält Kopiera värde Kopiera nyckel Produktfoto @@ -35,24 +71,24 @@ Language: sv_SE Nyckeln används redan för ett annat anpassat fält.\nAppen har för närvarande inte stöd för att skapa dubbletter av nycklar. Använd WP-admin för att duplicera en nyckel om det behövs. Lägg till anpassade fält Anpassat fält borttaget - Misslyckades att spara ändringar, försök igen + Skanning misslyckades. Försök igen senare Ändringar sparade Sparar ändringar + Misslyckades att spara ändringar, försök igen Det verkar som att du inte är ansluten till internet. Kontrollera att ditt Wi-Fi är på. Se till att mobildata är aktiverat i dina enhetsinställningar om du använder detta. - Skanning misslyckades. Försök igen senare Värde Nyckel Andra produkttyper, till exempel rörliga och virtuella, kommer att bli tillgängliga i framtida uppdateringar. - Endast enkla fysiska produkter kan användas med POS just nu. Avbryt Varaktighet Kampanj kommer köras tills du stoppar den. Specificera varaktigheten + Endast enkla fysiska produkter kan användas med POS just nu. till %1$s Schema Dagligt belopp - Hur mycket vill du spendera på din kampanj, och hur länge ska den köras? %1$s ➔ %2$s + Hur mycket vill du spendera på din kampanj, och hur länge ska den köras? Visa upp dina produkter för miljontals människor med Blaze och öka din försäljning Funderar du på hur du kan öka din försäljning? Det gick inte att läsa in anpassade fält @@ -60,35 +96,35 @@ Language: sv_SE Nedtonad bakgrund. Tryck för att avfärda dialogrutan. %1$s per vecka Kör tills jag stoppar den - Pågående från %1$s - veckobelopp %1$s per vecka, från och med %2$s Per vecka Återstående Totalt Klick Det verkar som att din enhet är i strömsparläge. \nVI kan inte tillhandahålla din butiksinformation medan det är aktiverat - Popup-meny med alternativ. Svep för att navigera bland objekt. - Öppna verktygsfältsmeny - Verktygsfält med kortläsarstatus. Menyn är öppen. Dubbeltryck för att interagera. - Verktygsfält med kortläsarstatus. Dubbeltryck för att interagera. + Pågående från %1$s + veckobelopp Meny inaktiverad Meny aktiverad - Kortläsare inte ansluten. Dubbeltryck för att ansluta Kortläsare ansluten + Kortläsare inte ansluten. Dubbeltryck för att ansluta + Popup-meny med alternativ. Svep för att navigera bland objekt. + Öppna verktygsfältsmeny + Verktygsfält med kortläsarstatus. Dubbeltryck för att interagera. + Verktygsfält med kortläsarstatus. Menyn är öppen. Dubbeltryck för att interagera. Nedtonad bakgrund. Tryck för att stänga menyn. Bockmarkeringsikon för lyckad betalning Ta bort den här varan från varukorgen + Dubbeltryck för att lära dig mer + Stäng + Öka din försäljning Eventuella pågående beställningar kommer att gå förlorade. Lämna Försäljningsplatsläge? - Stäng Nedtonad bakgrund. Tryck för att avfärda dialogrutan. Dubbeltryck för att avfärda dialogrutan Dialogruta – endast enkla produkter - Dubbeltryck för att lära dig mer Banner – endast enkla produkter Marknadsför dina produkter med Blaze-annonser och öka din försäljning nu. - Öka din försäljning Ta emot betalningar i farten En felaktig PIN-kod har angetts. Försök igen eller använd en annan betalningsmetod Meny @@ -99,30 +135,30 @@ Language: sv_SE Ny beställning OK + Skapa en beställning i butikshantering - För att ta betalt för en icke-enkel produkt, lämna POS och skapa en ny beställning från fliken Beställningar. Varför kan jag inte se mina produkter? Info Stäng - Läs mer Endast enkla fysiska produkter är kompatibla med POS just nu. Andra produkttyper, till exempel rörliga och virtuella, kommer att bli tillgängliga i framtida uppdateringar. Visar endast enkla produkter + För att ta betalt för en icke-enkel produkt, lämna POS och skapa en ny beställning från fliken Beställningar. + Läs mer Webbplatsadress - Google för WooCommerce Lägg till betald kampanj + Google för WooCommerce Öka försäljningen och generera mer trafik med Google Ads. Google-kampanjer Klar Din nya kampanj har skapats. Spännande tider väntar för din försäljning! - Redo att köra! Kunde inte skapa beställning Försök igen + Det gick inte ladda in produkter + Redo att köra! Ikon som indikerar fel Vill du försöka igen? - Det gick inte ladda in produkter POS stöder för närvarande bara enkla produkter POS stöder för närvarande bara enkla produkter – \nskapa en för att komma igång. - Inga produkter som stöds hittades Inga produkter + Inga produkter som stöds hittades Skaffa support Anslut din läsare Foto borttaget @@ -132,36 +168,35 @@ Language: sv_SE Klick Visningar Konvertering - Belopp Total försäljning + Belopp Nyckeltal Total försäljning: %1$s Belopp: %1$s Filtrera urval Varukorg är tom + %d artiklar Tryck på en produkt för att\nlägga till den i varukorgen Det gick inte att hämta summor. - %d artiklar Misslyckades att ladda upp den valda produktbilden. <b>Bra förfrågan!</b> Du har gett oss tillräckligt att arbeta med, men du kan lägga till mer information för att få ännu bättre resultat. + <b>Lägg till fler detaljer.</b> Ju fler detaljer du anger, desto bättre blir dina genererade detaljer. <b>Bra förfrågan!</b> Var gjordes den? <b>Det blir bättre.</b> Kan du beskriva passformen och eventuella särdrag hos varan? - <b>Lägg till fler detaljer.</b> Ju fler detaljer du anger, desto bättre blir dina genererade detaljer. Lägg till din produkts namn och viktiga funktioner, fördelar eller information som hjälper kunder att hitta den online. - Välj nästa alternativ - Välj föregående alternativ Generera igen Ångra redigeringar Alternativ %1$d av %2$d + Välj föregående alternativ + Välj nästa alternativ Visa alla kampanjer Skapa kampanj Klick Visningar - Betalkampanjsresultat - Marknadsför dina produkter i Google Sök, Google Shopping, Youtube, Gmail med mera. Öka försäljningen och generera mer trafik med Google Ads Google Ads-kampanjer - Inget + Betalkampanjsresultat + Marknadsför dina produkter i Google Sök, Google Shopping, Youtube, Gmail med mera. Inget telefonnummer Postnummer Ort @@ -170,7 +205,6 @@ Language: sv_SE Registreringsdatum Användarnamn Genomsnittligt beställningsvärde - Totalt spenderat belopp Beställningar Senast aktiv Plats @@ -178,62 +212,68 @@ Language: sv_SE Faktureringsadress Registrering Beställningar - Kund Inga produkter Kunder Få kundinsikter Kunder - Det gick inte att skanna texten från fotot. Försök igen Skannar bild Foto valt + Inget + Totalt spenderat belopp + Kund + Det gick inte att skanna texten från fotot. Försök igen Ta bort foto Byt ut foto Visa foto Namn, sammanfattning och beskrivning - Du kan redigera eller återskapa din produktinformation innan du sparar. Program - Google-kampanjer + Du kan redigera eller återskapa din produktinformation innan du sparar. Inga program under den här perioden + Google-kampanjer Anslut nu Varukorg Generera produktdetaljer Läs text från produktfoto Till exempel: Svart t-shirt i bomull, mjukt tyg, slitstarka sömmar, unik design - Berätta för oss om din produkt, vad det är och vad som gör produkten unik, och låt sedan AI:n göra sitt jobb. Startinformation Låt oss generera produktinformation åt dig - Ta emot kortbetalning + Berätta för oss om din produkt, vad det är och vad som gör produkten unik, och låt sedan AI:n göra sitt jobb. Totalt - Momser Delsumma Betalning lyckades Betalning misslyckades. Försök igen. Varukorgsikon Produkter - %d artikel - Rensa - Öka försäljningen och generera mer trafik med Google Ads Google för WooCommerce Inga regler för antal + Öka försäljningen och generera mer trafik med Google Ads + Ta emot kortbetalning + Rensa + %d artikel + Momser Målgrupp Avbryt Avsluta Avsluta POS - Ta bort %s från varukorg Kassa - Läsarens status okänd - Kassa - Läsare ansluten - Avsluta POS + Ta bort %s från varukorg Lägg till nya sektioner Inga produkter hittades för den valda lagerstatusen + Läsare ansluten + Avsluta POS + Läsarens status okänd + Kassa Det gick inte att läsa in lagerrapporten Ingen vara såld de senaste 30 dagarna %d varor sålda de senaste 30 dagarna - Försäljningsplatsläge Lågt lager - FRAKT Dela din feedback + Letar du efter fler insikter? + Produkter + Lagernivåer + Status + Försäljningsplatsläge + FRAKT Gör Woo frakt enkelt? Frakt tillagd. Redigera frakt @@ -243,99 +283,95 @@ Language: sv_SE Markera beställningen som slutförd Registrera transaktionsinformation i beställningsanteckning Lägg till nya sektioner för att anpassa din butikshanteringsupplevelse - Letar du efter fler insikter? - Produkter - Lagernivåer - Status Behöver du fortfarande hjälp? Kontakta oss - Det går inte att hämta rapporten över användning av rabattkoder - Ingen användning av rabattkoder under denna period Visa alla rabattkoder Användningar Rabattkoder Lager Visa alla meddelanden - Det gick inte att läsa in toppresterande produkter N/A - Växel - Kontanter mottagna + Det går inte att hämta rapporten över användning av rabattkoder + Ingen användning av rabattkoder under denna period + Det gick inte att läsa in toppresterande produkter Mest aktiva rabattkoder + Kontanter mottagna + Växel Ta emot betalning (%s) + Status + Visa alla beställningar Visa alla recensioner - Inga recensioner matchar det valda filtret, testa att ändra filter Inga recensioner hittades - Status De senaste recensionerna De senaste beställningarna - Visa alla beställningar + Inga recensioner matchar det valda filtret, testa att ändra filter Öppna listrutan för filter Rensa överordnad kategori Fel vid hämtning av produkter! - Välj en fraktmetod - Frakt Namn Metod - Lägg till frakt - Det gick inte att hämta dina fraktmetoder. Försök igen Metod Ogiltigt värde - Konfigurera din butik + Frakt + Lägg till frakt + Välj en fraktmetod + Det gick inte att hämta dina fraktmetoder. Försök igen Anpassa + Konfigurera din butik Visa alla kampanjer Föreslagen produkt Försök att läsa in det här kortet igen. Om problemet kvarstår, <a href=\"support\">kontakta supporten</a>. - Kan inte ladda data Dölj %s Slutförd Feedback - Se till att du kör den senaste versionen av WooCommerce på din webbplats och att du har WooCommerce Analytics aktiverat. + Kan inte ladda data Vi kan inte visa din\n butiks analys + Se till att du kör den senaste versionen av WooCommerce på din webbplats och att du har WooCommerce Analytics aktiverat. + Inte tillgänglig + Anpassad Visa alla uppgifter Sessionsanalysen bygger på antalet unika besökare, vilket inte är tillgängligt för anpassade datumintervall Sessionsdata ej tillgänglig - Inte tillgänglig Prestanda - Anpassad Ändra datumintervall-knapp Bilderna är inte tillgängliga, eftersom din webbplats är satt som Privat. Du kan ändra detta genom att växla till läget Kommer snart.\n Kortval för analys Avbryt Avsluta ändå - Det verkar som att du inte har godkänt appanslutningen än. Är du säker på att du vill lämna sidan? - Välj en bild med en minsta storlek på 400x400 pixlar Ogiltig bild + Inga anslutningsproblem + Det verkar som att du inte har godkänt appanslutningen än. Är du säker på att du vill lämna sidan? Det verkar som att användarnamnet eller lösenordet som du angav är felaktigt. Dubbelkolla dina autentiseringsuppgifter och försök igen. Om dina data fortfarande inte laddas, kontakta vårt supportteam för att få hjälp. - Inga anslutningsproblem + Välj en bild med en minsta storlek på 400x400 pixlar Gå tillbaka till föregående skärm Försök ansluta igen Ansluter till din webbplats Vi kan inte ansluta till WordPress.com för tillfället.\n\nFörsök igen om några minuter, eller kontakta vårt supportteam så hjälper vi dig. - Vänta medan vi försöker identifiera ditt anslutningsproblem. Felsök anslutning Presentkort Använt + Vänta medan vi försöker identifiera ditt anslutningsproblem. Inga presentkort denna period Kontakta support Fortsätt Om du stöter på problem, kontakta vårt supportteam. + Vi kunde inte logga in i din butik + Lägg till ett anpassat belopp 3. När anslutningen är klar kommer du att loggas in i din butik. 2. När du uppmanas till det, godkänn anslutningen genom att trycka på bekräftelseknappen. 1. Börja med att logga in med dina webbplatsautentiseringsuppgifter. Följ dessa steg för att ansluta Woo-appen direkt till din butik med ett applikationslösenord. Detta kan bero på att din butik har några extra säkerhetssteg på plats. - Vi kunde inte logga in i din butik Din beställningsinformation kommer att visas här när du har gjort en beställning. Ingen beställningsinformation än - Lägg till ett anpassat belopp För att ange ett betalningsbelopp, lägg till\nett anpassat belopp till din nya beställning. Vi har kombinerat betalningsmottagning med\nbeställningsskapande för förbättrad åtkomst\noch mer kraft. - Ta emot betalning \nhar flyttat Paket Paket sålda Paket Paket sålda Blaze-kampanjer + Ta emot betalning \nhar flyttat Toppresterande Är du säker på att du vill kassera ändringarna som du har gjort för den här produkten? Du är på väg att kassera ändringarna för %s @@ -345,129 +381,129 @@ Language: sv_SE Prenumerationer Prenumerationer Tolkar förhandsgranskning … - Ett fel uppstod vid inläsningen av installerade tillägg - Hanteras automatiskt Inaktivt Uppdatering tillgänglig (%s) - Uppdaterat - Butiksnamn Tar bort kategori Uppdaterar kategori - Fel vid borttagning av kategori Produktkategori borttagen Produktkategori uppdaterad + Butiksnamn Det gick inte att ladda domänförslag + Ett fel uppstod vid inläsningen av installerade tillägg + Hanteras automatiskt + Uppdaterat + Fel vid borttagning av kategori Förslag Skriv en domän Välj en domän - Visa alla butiksanalyser En gång om året En gång i månaden En gång i veckan En gång om dagen - En gång i timmen - %s intervall Anslut en annan butik Starta en ny butik Butiksnamn + En gång i timmen + %s intervall + Visa alla butiksanalyser Vänta … Uppdateringar lagerstatus Något gick fel. Försök igen. - Uppdaterade lagerstatusar Variabla produkter kan inte uppdateras Hanterade produkter kan inte uppdateras + Uppdaterade lagerstatusar 1 variabel produkt kommer att ignoreras. - 1 produkt med hanterad lagerkvantitet kommer att ignoreras. Lagerstatus kommer att uppdateras för 1 produkt. - %1$d variabla produkter kommer att ignoreras. - %1$d produkter med hanterad lagerkvantitet kommer att ignoreras. - Lagerstatus kommer att uppdateras för %1$d produkter. Nuvarande lagerstatus är %1$s Nuvarande lagerstatus är blandat KLART - Uppdatera lagerstatus - Logga in med dina inloggningsuppgifter för webbplatsen WooCommerce-version Installerade tillägg Tillägg - Ljudet för orderaviseringar har ändrats. Använd den här knappen för att återställa \"cha-ching\"-ljudet. - Uppdatera lagerstatus - Vill du flytta denna beställning till papperskorgen? Flytta till papperskorgen Räkna om Skanna produkter + Vill du flytta denna beställning till papperskorgen? + Lagerstatus kommer att uppdateras för %1$d produkter. + Uppdatera lagerstatus + Uppdatera lagerstatus + 1 produkt med hanterad lagerkvantitet kommer att ignoreras. + %1$d variabla produkter kommer att ignoreras. + %1$d produkter med hanterad lagerkvantitet kommer att ignoreras. + Logga in med dina inloggningsuppgifter för webbplatsen + Ljudet för orderaviseringar har ändrats. Använd den här knappen för att återställa \"cha-ching\"-ljudet. Ordersammanfattning Ett fel uppstod när ordern togs bort Ordern borttagen Det verkar vara ett problem med din webbplats.\n\nKontakta ditt webbhotell för vidare hjälp. + Det verkar som att du inte är ansluten till internet.\n\nKontrollera att ditt Wi-Fi är på. Se till att mobildata är aktiverat i dina enhetsinställningar om du använder detta. + Din webbplats verkar ta för lång tid att svara.\n\nKontakta ditt webbhotell för ytterligare hjälp. Det verkar ha uppstått ett problem med din Jetpack-anslutning.\n\nMen oroa dig inte, vårt supportteam finns här om du behöver hjälp. Kontakta oss så hjälper vi dig. Det verkar som att vi inte kan arbeta korrekt med din webbplats svar.\n\nMen oroa dig inte, vårt supportteam finns här om du behöver hjälp. Kontakta oss så hjälper vi dig. - Din webbplats verkar ta för lång tid att svara.\n\nKontakta ditt webbhotell för ytterligare hjälp. - Det verkar som att du inte är ansluten till internet.\n\nKontrollera att ditt Wi-Fi är på. Se till att mobildata är aktiverat i dina enhetsinställningar om du använder detta. - Ingen produkt vald Läs mer Kontakta supporten - Hämtar dina webbplatsbeställningar - Ansluter till WordPress.com-servrar Internetanslutning + Ingen produkt vald Lägg till statistik för anpassade datumintervall + Ansluter till WordPress.com-servrar + Hämtar dina webbplatsbeställningar Ingen plats hittades.\nFörsök igen. - Sidvisningar under session - Enhetstyp Medium Medium - Källa - Källtyp Okänd Mobilapp Webbadministratör Direkt Källa: %1$s - Hänvisning: %1$s - Organisk: %1$s - Ursprung - Beställningstillskrivning - Kontakta via Telegram - Kontakta via WhatsApp ID: %d Kund Produkt Gäst + Källa + Källtyp + Enhetstyp + Hänvisning: %1$s + Organisk: %1$s + Kontakta via Telegram + Kontakta via WhatsApp Denna användare är en gäst, och gäster kan inte användas för att filtrera beställningar. Försök igen senare eller kontakta oss så hjälper vi dig gärna + Sidvisningar under session + Ursprung + Beställningstillskrivning Det tar lång tid för din webbplats att svara Visa detaljer Fraktmoms Anpassa analys + Avbryt kampanj + Skaffa support Något är fel.\nVi kunde inte skapa din kampanj. Det gick inte att hämta information om kampanjbilden Uppladdning av kampanjbild misslyckades. - Avbryt kampanj - Skaffa support Försök igen eller kontakta supporten för hjälp. - Kampanjen kunde inte skapas - Kampanjen kunde inte skapas Skapar din kampanj Klar - Vi granskar din kampanj. Den kommer att gå live inom 24 timmar. Spännande tider väntar för din försäljning. - Allt är klart att köras. Nyckeln finns redan - Den sista URL:en är för lång Värde Nyckel - Destination: %s + Lägg till + Lägg till bild + Lägg till kreditkort Lägg till parameter - Kreditkortet är nu tillagt + Betalningsmetod Lägg till nytt kort + Kampanjen kunde inte skapas + Kampanjen kunde inte skapas + Vi granskar din kampanj. Den kommer att gå live inom 24 timmar. Spännande tider väntar för din försäljning. + Allt är klart att köras. + Den sista URL:en är för lång + Destination: %s + Kreditkortet är nu tillagt Kreditkorten hämtas från följande WordPress.com-konto: %1$s <%2$s> Alla transaktioner är säkra och krypterade - Lägg till kreditkort Lägg till en ny betalningsmetod - Betalningsmetod Det gick inte att uppskatta antalet visningar. Försök igen? - Lägg till Lägg till en slogan och en beskrivning för din Blaze-kampanj - Lägg till bild Lägg till en bild till Blaze-kampanjen Draghandtag Kort för analys @@ -477,63 +513,63 @@ Language: sv_SE URL-parametrar Mål-URL Ange manuellt - Sökning misslyckades.\nFörsök igen Börja skriva land, delstat eller stad för att se tillgängliga alternativ Genom att klicka på \"Skicka kampanj\" godkänner du våra <a href=\'termsOfService\'><u>användarvillkor</u></a> och vår <a href=\'advertisingPolicy\'><u>annonspolicy</u></a> och samtycker till att din betalningsmetod debiteras för den budget och den varaktighet som du väljer. <a href=\'learnMore\'><u>Läs mer</u></a> om hur budgetar och betalningar för marknadsförda inlägg fungerar. + Sökning misslyckades.\nFörsök igen Skicka in kampanj - Laddning av betalningsmetoder misslyckades. Försök igen genom att klicka här! Lägg till betalningsmetod Laddar in betalningsmetoder Totalt - Blaze-kampanj - Betalning totalt Betalning Sök platser + Blaze-kampanj + Laddning av betalningsmetoder misslyckades. Försök igen genom att klicka här! + Betalning totalt Det gick inte att lagra kvittot Det gick inte att ladda ner kvittot Det gick inte att hitta någon applikation som kvittot kan delas till Vi kunde inte ladda något kvitto för den här beställningen - Föreslaget av AI - %d tecken återstår Beskrivning Slogan Ändra bild Tillämpa - Startdatum %1$s dagar - Visningar återspeglar hur ofta din annons visas för potentiella kunder.\n\n\n Exakta siffror kan inte garanteras på grund av fluktuerande onlinetrafik och användarbeteende, men vi strävar efter att annonsens faktiska antal visningar ska ligga så nära ditt målantal som möjligt.\n\n\n Kom ihåg att visningar handlar om synlighet, inte om åtgärder som vidtas av tittarna. Klar - Visningar Uppdatera Redigera - Uppskattat antal personer som nås per dag - %1$s dagligen - i %1$s dagar Ställ in din budget - Alla + i %1$s dagar %1$s dagar från %2$s + Alla + %d tecken återstår + %1$s dagligen + Föreslaget av AI + Visningar + Uppskattat antal personer som nås per dag + Visningar återspeglar hur ofta din annons visas för potentiella kunder.\n\n\n Exakta siffror kan inte garanteras på grund av fluktuerande onlinetrafik och användarbeteende, men vi strävar efter att annonsens faktiska antal visningar ska ligga så nära ditt målantal som möjligt.\n\n\n Kom ihåg att visningar handlar om synlighet, inte om åtgärder som vidtas av tittarna. + Startdatum Visa det inte igen Påminn mig senare Har du tid en minut? Hjälp oss att förbättra våra AI-assisterade funktioner genom lite snabb feedback. Bekräfta detaljer - Annonsdestination Intressen Plats Enheter Språk Budget Detaljer + Förhandsgranska + Annonsdestination Handla nu Redigera annons - Förhandsgranska Inaktiverad (originalstorlek) - Produktval Välj produkt %s + <b>Välj en produkt:</b> Välj vad som ska marknadsföras med Blaze. + Produktval <b>Gå live:</b> Se din kampanj starta och följ dess resultat. <b>Snabbgranskning:</b> Skicka in din annons för en snabb moderatorkontroll. <b>Ange din budget:</b> Bestäm hur mycket du vill spendera och kampanjens längd. <b>Anpassa målgrupp:</b> Välj målgrupp baserat på plats eller intressen och se potentiell räckvidd. - <b>Välj en produkt:</b> Välj vad som ska marknadsföras med Blaze. Hantera lager Lager inte hanterat Lär dig hur Blaze fungerar @@ -544,49 +580,53 @@ Language: sv_SE Global räckvidd på ett enkelt sätt Lansera annonser på några minuter – ingen erfarenhet eller stor budget behövs, från bara $5 per dag. Snabb start, stor påverkan + Ange kod + Använd %1$s Vårt verktyg är utformat för att ge handlare möjlighet att snabbt och enkelt skapa annonskampanjer för maximal trafikökning. Marknadsför Redo att marknadsföra Visa upp dina produkter för miljontals människor - Använd %1$s SENASTE INSÄTTNING Expandera/minimera beställningssummor Ta emot betalning Koden bör vara i formatet XXXX-XXXX-XXXX-XXXX - Ange kod - Rabattkod + Rabattkoder Misslyckades att ladda teman. Konfiguration slutförd - Uppdatering av kvantitet är ångrad Kunde inte ladda ditt nuvarande tema Stationär dator Läsplatta Mobil tryck här - Tyvärr verkar det vara ett problem med hämtningen av mallen. %1$s för en live-demo. - Du hittar ditt perfekta tema i WooCommerce-temabutiken. Nuvarande tema Prova ett nytt utseende Börja undersökningen Vi värdesätter dina åsikter! + Behöver du hjälp? <a href=\'\'>Kontakta oss</a> + Uppdatering av kvantitet är ångrad + Tyvärr verkar det vara ett problem med hämtningen av mallen. %1$s för en live-demo. + Du hittar ditt perfekta tema i WooCommerce-temabutiken. Om du aktiverar alternativet Betala personligen kan kunden betala kontant eller med kort för onlinebeställningar vid leverans.\n\nBeställningar kan fortfarande skapas manuellt utan att aktivera denna funktion. Vill du lägga till alternativet Betala personligen i din kassa? - Behöver du hjälp? <a href=\'\'>Kontakta oss</a> Återbetala anpassat belopp - Återbetalning av anpassade belopp Skanna produktens streckkod Lägg till presentkort + Återbetalning av anpassade belopp Produkt Antal Ursprungligt antal Något gick fel. Försök igen - Antal uppdaterat: %s Visa produktdetaljer Uppdatera antal + AKTIVERA LJUD + % + 0 + Antal uppdaterat: %s Antal + 1 + Temaaktivering misslyckades, försök igen! + BEHÅLL TYST Produkt med SKU: %s är inte lagerhanterad. Försök igen. Produkt med SKU: %s hittades inte. Försök igen. - Temaaktivering misslyckades, försök igen! Ljudet för beställningsnotiser har inaktiverats. Slå på det igen för att höra \"ka-ching\" vid varje ny försäljning. Aktivera ka-ching-ljud Skanna streckkoden för att uppdatera lagret @@ -594,23 +634,19 @@ Language: sv_SE Testnotis TESTA LJUD Klart! \"Ka-ching\"-ljudet kommer nu att höras för varje ny beställning. - BEHÅLL TYST - AKTIVERA LJUD Aktivera det igen för att höra \"ka-ching\" vid varje ny försäljning. Håll koll på dina kunders beställningar. Ka-ching-ljud av Antal beställningar - % - 0 En procentandel av beställningens totala belopp Ett fast belopp Hur vill du lägga till ditt anpassade belopp? - Procentandel av beställningens totala belopp %1$s Ta bort anpassat belopp - Temat har aktiverats + Procentandel av beställningens totala belopp %1$s Hem Tryck för att visa Sidor på denna mall Förhandsgranska + Temat har aktiverats Letar du efter fler? Du kan alltid ändra det senare i inställningar Välj ett tema @@ -626,98 +662,98 @@ Language: sv_SE Tackbrev Obs! För att den här inställningen ska kunna aktiveras får prenumerationen inte ha en gratis provperiod eller ett synkroniserat förnyelsedatum. Aktivera detta för att endast debitera frakt en gång vid den första ordern. + Dokument och andra filer på enhet Aktiverad Engångsfrakt - Dokument och andra filer på enhet ✨ Skapa tackbrev Debitera moms Tillgängliga medel sätts in automatiskt, varje %s. Tillgängliga medel sätts in automatiskt, varje dag. Medlen blir tillgängliga efter att ha inväntat granskning i %d dagar. Välj en variant - Välj variant ”%1$s” -> %2$s välj en variant + Välj %1$s %1$s objekt valda %1$s objekt valda - Välj %1$s fler än %1$s objekt fler än %1$s objekt färre än %1$s objekt mellan %1$s och %2$s objekt %d objekt %d objekt + Välj variant Ändra produktantalet från %1$.2f till %2$.2f Spara konfiguration Konfiguration - Produkt %s Konfigurera - Alternativt kommer registreringsavgiften att debiteras omedelbart, även om produkten har en gratis provperiod eller synkroniserade betalningsdatum. En produktprenumeration med varianter Variabel prenumerationsprodukt - En unik produktprenumeration som möjliggör återkommande betalningar Enkel prenumerationsprodukt + Produkt %s + Alternativt kommer registreringsavgiften att debiteras omedelbart, även om produkten har en gratis provperiod eller synkroniserade betalningsdatum. + En unik produktprenumeration som möjliggör återkommande betalningar En valfri tidsperiod att vänta innan den första återkommande betalningen debiteras. Eventuella registreringsavgifter kommer fortfarande att debiteras vid prenumerationens start. Provperioden får inte överstiga: 90 dagar, 52 veckor, 24 månader eller 5 år. Gratis provperiod på prenumeration Prenumerationens utgångsdatum - ANPASSADE BELOPP - BETALNING TOTALT - ORDERANTECKNINGAR PRODUKTER PRODUKT KUND - Ange din säkerhetsnyckel för att fortsätta. - Det uppstod vissa problem med säkerhetsnyckelsinloggningen + ANPASSADE BELOPP + BETALNING TOTALT + ORDERANTECKNINGAR Använd en säkerhetsnyckel Period + Ange din säkerhetsnyckel för att fortsätta. + Det uppstod vissa problem med säkerhetsnyckelsinloggningen + Misslyckades + Avbruten + Betald + Beräknad Faktureringsintervall Rea Okänd - Misslyckades - Avbruten På väg Väntande - Betald - Beräknad Minimera/maximera insättningssammanfattningen Läs mer om när du får dina medel - Tillgängliga medel sätts in automatiskt, varje månad den %s. - Medlen blir tillgängliga efter att ha inväntat granskning i %d dag. - Väntande medel - Tillgängliga medel Momser Produkter + Tillgängliga medel + Väntande medel + Tillgängliga medel sätts in automatiskt, varje månad den %s. + Medlen blir tillgängliga efter att ha inväntat granskning i %d dag. Betalning totalt E-postadress eller användarnamn - Det går inte att skapa en order med anpassat belopp Ange anpassat namn Lägg till anpassat belopp Namn Belopp Anpassat belopp + Det går inte att skapa en order med anpassat belopp Anslut Jetpack via din adminsida i en webbläsare eller kontakta supporten. Ett fel uppstod vid kommunikationen med din webbplats. Anpassade belopp Marknadsför med Blaze Jag förstår Annonsen har skickats in för godkännande. Vi skickar en bekräftelse via e-post när den är godkänd och aktiverad. - Klart! Starta Blaze-kampanj nu - Följ upp resultat samt starta och stoppa din Blaze-kampanj när som helst. Nå miljoner på WordPress- och Tumblr-webbplatser. + Klart! + Följ upp resultat samt starta och stoppa din Blaze-kampanj när som helst. Ta kontrollen för bara några dollar om dagen. Det är budgetvänligt. - Marknadsför din produkt på bara några minuter. + Minska produktantal + Skanna streckkod + Minimera/expandera produktkort Få mer försäljning i din butik med Blaze - Det uppstod ett fel vid uppdateringen av listan över kampanjer. Försök igen senare. + Marknadsför din produkt på bara några minuter. Välj mediekälla Ingen text upptäckt. Välj ett annat förpackningsfoto eller ange produktinformation manuellt. Lägg till produkt - Skanna streckkod - Minimera/expandera produktkort - Minska produktantal - Öka produkantal + Det uppstod ett fel vid uppdateringen av listan över kampanjer. Försök igen senare. Lägg till anpassat belopp Pris efter rabatt + Öka produkantal Föregående beställning Nästa beställning Kampanjinformation @@ -731,23 +767,23 @@ Language: sv_SE Prova att genomföra en %s-betalning med ditt betal- eller kreditkort.\nBetalningen kommer att återbetalas när du är klar. Det är enkelt, säkert och privat. Ta emot alla typer av personliga betalningar, direkt\ni din telefon. Ingen extra hårdvara behövs. - Avvisad - Har slutförts Aktiv Under granskning Skapa kampanj + Avvisad + Har slutförts Öka synligheten och få dina produkter sålda snabbt. Blaze-kampanj Contactless Symbol är ett varumärke som ägs av och används med tillåtelse av EMVCo, LLC. 5. När du ser \"Klar\"-markeringen kommer din butik att behandla betalningen och transaktionen är slutförd. 3. Håll fram din telefon mot kunden. 2. Tryck på \"Ta emot betalning\" och välj \"Tryck för att betala\". - 1. Skapa en beställning Hur det fungerar Lär dig mer om kortläsare För att ta emot betalningar över denna gräns, överväg att köpa en kortläsare som accepterar PIN-inmatning. Vi stöder inte PIN-inmatning med Tryck för att betala på Android. I %1$s kräver vissa kort en PIN för kontaktlösa transaktioner över %2$s. + 1. Skapa en beställning Viktig information Med Tryck för att betala kan du ta emot alla typer av kontaktlösa betalningar, från fysiska betal- och kreditkort till digitala plånböcker, utan att behöva köpa en fysisk kortläsare. Vad är Tryck för att betala? @@ -769,24 +805,25 @@ Language: sv_SE Ange en ny momssats för den här beställningen Lägg till momssats automatiskt Prova att inaktivera filtret för olästa produktrecensioner för att se alla dina produktrecensioner - Inga olästa produktrecensioner Övertygande - Blommig Formell - Avslappnad - Ton och röst Detaljer Produktnamn + Inga olästa produktrecensioner + Blommig + Avslappnad + Ton och röst Förhandsgranska Exempelvis mjukt tyg, slitstarka sömmar, unik design Drivs med AI. <a href=\'guidelines\'><u>Lär dig mer</u></a>. Lägg till en produkt och detaljerna manuellt Lägg till manuellt - Snabbgenerera information åt dig Skapa en produkt med AI Lägg till en produkt Endast olästa recensioner + Snabbgenerera information åt dig Redigera momssatsinställning + Betalningsmetoder Detta kommer inte att påverka onlinebeställningar Lägg till den här momssatsen till alla skapade beställningar Redigera momssatser @@ -794,15 +831,14 @@ Language: sv_SE Lägg till momssatser i adminpanelen. Endast momssatser med platsinformation kommer att visas här. Vi kunde inte hitta några momssatser Upptäck andra betalningsleverantörer och \nvälj en betalningsleverantör. - Betalningsmetoder Bilder och videoklipp på enhet Lös nu Slutför inställning Ange momssats Aktivera Ange ny momssats - WooPayments Ställ in + WooPayments Redigera momssatser i adminpanelen Detta kommer att ändra kundens adress till platsen för den momssats du väljer. Knapp som öppnar dialogrutan för information om momssatser @@ -821,15 +857,15 @@ Language: sv_SE <a href=\'learnMore\'><u>Lär dig mer</u></a> om att verifiera din information med WooPayments. Börja installationen Vi har slagit oss ihop med Stripe för WooPayments. Du kommer att bli omdirigerad till Stripes webbplats för registrering. Vi kommer att be dig att kontrollera dina företagsuppgifter och din betalningsinformation. - Dina WooPayments-aviseringar kommer att skickas till e-postadressen som är kopplad till ditt WordPress.com-konto. Föredrar du att använda ett nytt konto? <a href=\'learnMore\'><u>Mer information finns här.</u></a> - Innan du startar konfigurationen 4–6 minuter Beräknad installationstid + Innan du startar konfigurationen + Dina WooPayments-aviseringar kommer att skickas till e-postadressen som är kopplad till ditt WordPress.com-konto. Föredrar du att använda ett nytt konto? <a href=\'learnMore\'><u>Mer information finns här.</u></a> Hantera betalningar utan ansträngning med WooPayments, allt på en och samma plats. Ta emot kortbetalningar, Apple Pay-betalningar, personliga betalningar och över 135 olika valutor, helt utan installationskostnader eller månadsavgifter. Det gick inte att spara butiksnamnet. Försök igen. - Sparar nytt butiksnamn … Butiksnamn inställt. Butiksnamn inställt. \n För att ändra igen, gå till butiksinställningarna. + Sparar nytt butiksnamn … Uppdatera butiksnamn Grattis! Du har gått igenom konfigurationen och ditt betalningssystem är redo att användas. Du gjorde det! @@ -850,13 +886,13 @@ Language: sv_SE Beställningssumma Beräknad procentandel Beräknat belopp - Butiksnamn Att anpassa ditt butiksnamn kan också förbättra din butiks sökmotoroptimering. + Butiksnamn Namnge din butik Aktivera NFC Leveranspaket för små kvantiteter (märkningar krävs) - LTD QTY-markpaket – Aerosoler, spraydesinfektionsmedel, sprayfärg, hårspray, propan, butan, rengöringsprodukter, osv. - Parfymer, nagellack, nagellackborttagningsmedel, lösningsmedel, handsprit, tvättsprit, etanolbaserade produkter, osv. - Andra ytmaterial i begränsad mängd (kosmetika, rengöringsprodukter, färger, osv.) Tändarpaket – Auktoriserade tändare + LTD QTY-markpaket – Aerosoler, spraydesinfektionsmedel, sprayfärg, hårspray, propan, butan, rengöringsprodukter, osv. - Parfymer, nagellack, nagellackborttagningsmedel, lösningsmedel, handsprit, tvättsprit, etanolbaserade produkter, osv. - Andra ytmaterial i begränsad mängd (kosmetika, rengöringsprodukter, färger, osv.) ID8000-konsumentvarupaket – Luftkvalificerade ID8000-konsumentvaror (icke brandfarliga aerosoler, brandfarliga brännbara vätskor, giftiga ämnen, diverse farliga material) Farliga material endast för markleverans (för föremål som inte är listade, men som är begränsade till endast yta) Undantagna kvantitetsförsörjningspaket (t.ex. små volymer av brandfarliga vätskor och frätande, giftiga eller miljöfarliga material – märkning krävs) @@ -879,56 +915,56 @@ Language: sv_SE Klass 4 – Paket (Brandfarliga fasta ämnen) Klass 3 – Paket (Handdesinfektionsmedel, tvättsprit, etanolbaserade produkter, brandfarliga vätskor, osv.) Klass 1 – Paket med leksaksdrivmedel/säkerhetssäkringar - Luftkvalificerat etanolpaket – (godkända försändelser av parfymer och handsprit) OK + Luftkvalificerat etanolpaket – (godkända försändelser av parfymer och handsprit) Potentiellt farligt material inkluderar varor såsom batterier, torris, brandfarliga vätskor, aerosoler, ammunition, fyrverkerier, nagellack, parfym, färg, lösningsmedel med mera. Farliga varor måste skickas i separata paket. Innehåller farliga material Ange produktrubrik. - E-handelsplattformen som växer tillsammans med dig Variabel prenumeration + E-handelsplattformen som växer tillsammans med dig Ta bort rabattkod Alla gillar ett erbjudande Du har inte skapat några rabattkoder ännu. Skapa en rabattkod för att tillämpa den på denna beställning. Gå till rabattkoder Välj en rabattkod - Misslyckades skapa rabattkod Rabattkod skapad Skapa Skapa rabattkod Skapa %1$s Redigera rabattkod Skapa en fast totalrabatt för valda produkter + Misslyckades skapa rabattkod Skapa en fast totalrabatt för hela varukorgen Skapa en procentuell rabatt för valda produkter Fast produktrabatt Fast varukorgsrabatt Procentuell rabatt - Kupongtyp – fast produkt - Kupongtyp – fast kundvagn - Kupongtyp – procentuell rabatt Skapa rabattkod Lägg till rabattkod Starta testbeställning + Sök efter kunder efter + Lägg till detaljer manuellt + Prova en testbeställning + Prova en testbeställning + Kupongtyp – fast produkt + Kupongtyp – fast kundvagn + Kupongtyp – procentuell rabatt Använd appen för att behandla återbetalningen för testbeställningen Slutför betalningen och vänta på en push-avisering om beställningen i din WooCommerce-app. Välj din testprodukt, lägg till i kundvagn och slutför i kassan på den webbutiken som en riktig kund. Tryck på knappen nedan för att bli vidarebefordrad till din onlinebutik via en webbläsare. - Prova en testbeställning - Prova en testbeställning Kör en testbeställning för att kontrollera att din WooCommerce-process levererar en sömlös kundupplevelse - Lägg till detaljer manuellt - Sök efter kunder efter Annat skäl (vänligen specificera) Jag är en del av ett team och vi måste fatta beslutet kollektivt. - Jag anser att priset på tjänsten är en viktig faktor i mitt beslut. Jag utvärderar och jämför din tjänst med andra på marknaden. Jag utforskar och utvärderar fortfarande funktionerna och fördelarna med appen. Hjälp oss att förstå dina prenumerationsbeslut. Din feedback är viktig. + Jag anser att priset på tjänsten är en viktig faktor i mitt beslut. Ingen e-postadress Inget namn - Sök efter en befintlig kund eller Senast uppdaterat %s (Uppdateras var 30:e minut) Senast uppdaterat %s + Sök efter en befintlig kund eller <a href=\'\'>Läs mer</a> om att ta emot betalningar med Tryck för att betala på Android Ta emot betalning Du kan inte lägga till produkter som inte har något specificerat pris @@ -936,136 +972,136 @@ Language: sv_SE lägg till kund Gå till inställningar Avbryt + Belopp (%1$s) Bevilja + Vi kunde inte hitta en rabattkod med den koden. Försök igen Du har nekat kameraåtkomst permanent. Det krävs för streckkodsskanning. Aktivera det i appinställningarna Kameraåtkomst krävs för streckkodsskanning. Bevilja kameraåtkomst Något gick fel när din rabattkod skulle valideras. Försök igen - Vi kunde inte hitta en rabattkod med den koden. Försök igen - Belopp (%1$s) Rabatt %1$s – %1$s - Totala rabatter - Rabatt Belopp (%1$s) - Manuell rabatt kunde inte tillämpas. Ta bort rabattkoder först + Rabatt Rabatt är inte ett giltigt nummer Rabatt kan inte vara större än priset Ta bort rabatt + Totala rabatter + Manuell rabatt kunde inte tillämpas. Ta bort rabattkoder först Knapptext Verktygstipsmeddelande. \n Detta kan innehålla flera rader. Verktygstipsrubrik - Jag förstår - Använd vårt AI-drivna verktyg för att snabbt generera produktbeskrivningar. Det är bara att ange nyckelord så gör vi resten. ✨ Skriv med AI + Jag förstår Generera en beskrivning med AI - Det uppstod ett problem när produktbeskrivningen skulle genereras. Försök igen senare. + Använd vårt AI-drivna verktyg för att snabbt generera produktbeskrivningar. Det är bara att ange nyckelord så gör vi resten. Beskrivning genererad av AI Drivs med AI. <a href=\'\'><u>Lär dig mer</u></a>. + Det uppstod ett problem när produktbeskrivningen skulle genereras. Försök igen senare. Tryck för att betala på Android är inte tillgängligt i ditt land än. Håll ögonen öppna. Din enhet behöver ha tjänsten Google Play för att du ska kunna använda Tryck för att betala på Android. För att ta emot personliga betalningar behöver du installera tjänsten Google Play eller köpa en Bluetooth-kortläsare. För att använda Tryck för att betala på Android behöver du Android 10 eller senare. För att ta emot personliga betalningar behöver du uppdatera Android eller köpa en Bluetooth-kortläsare. Din enhet behöver ha ett NFC-chip för att du ska kunna använda Tryck för att betala på Android. För att ta emot personliga betalningar behöver du köpa en Bluetooth-kortläsare. - Tryck för att betala är inte tillgängligt - Kontrollera kraven + Vi kunde inte ladda dina data. Felsökning + Kontrollera kraven + Tryck för att betala är inte tillgängligt Detta kan bero på en tilläggskonflikt. Försök igen senare eller kontakta oss så hjälper vi dig gärna. - Vi kunde inte ladda dina data. Jag förstår Tänk på att den här produktbeskrivningen har genererats med vårt AI-drivna verktyg. Granska och redigera innehållet för att säkerställa att det överensstämmer med ditt varumärke och ditt budskap. + Skanna streckkod + Användarnamn + Namn + E-post + Fler inställningar + Kanske senare Bra start! Är den genererade\nbeskrivningen beskrivning användbar? Generera igen - Framhäv din produkts unika funktioner och målgrupp med nyckelord för en skräddarsydd beskrivning. - Exempel: krukväxt, kaktus, växt, dekorativ, lättskött Ange ditt produktnamn Skriv en beskrivning + Framhäv din produkts unika funktioner och målgrupp med nyckelord för en skräddarsydd beskrivning. + Exempel: krukväxt, kaktus, växt, dekorativ, lättskött Kameraåtkomst krävs för streckkodsskanning. - Skanna streckkod - Användarnamn - Namn - E-post Tillämpade rabattkoder - Fler inställningar - Kanske senare Skriv igen - En PIN-kod krävs, men Tryck för att betala stöder inte detta än. Överväg att använda en extern kortläsare Köp en kortläsare Rabattkod kunde inte tillämpas och togs bort från beställningen - Det gick inte att generera meddelandet för delning. Försök igen. + En PIN-kod krävs, men Tryck för att betala stöder inte detta än. Överväg att använda en extern kortläsare Lär dig mer om vår AI-funktion Lägg till ett valfritt meddelande - Skriver … Skriv med AI Marknadsför produkter med Blaze Blaze - AI-innehållsgenerator tillgänglig Marknadsför med Blaze + Det gick inte att generera meddelandet för delning. Försök igen. + AI-innehållsgenerator tillgänglig + Skriver … Dela produkt Grattis. Du är ett steg närmare att kunna lansera din nya butik. Den första produkten har skapats 🎉 Systemet avslutade Woo-appen medan den kördes i bakgrunden. Du kan prova att använda den igen. Systemet avslutade Woo-appen medan den kördes i bakgrunden. Du kan prova att använda den igen. Kortet togs bort för tidigt - Variationsprodukt - Vår cookiepolicy förklarar hur vi och andra använder cookies och hur du kan hantera dem. - Cookiepolicy - Din information hjälper oss att förbättra våra produkter, marknadsföring och personifiera din upplevelse på WooCommerce. Integritetspolicy - Det uppstod ett fel när dina integritetsval skulle sparas. Spara Inställningar Tillåt oss att optimera prestandan genom att samla in information om hur användare interagerar med våra mobilappar. Analys Hantera integritet + Din information hjälper oss att förbättra våra produkter, marknadsföring och personifiera din upplevelse på WooCommerce. + Variationsprodukt + Vår cookiepolicy förklarar hur vi och andra använder cookies och hur du kan hantera dem. + Cookiepolicy + Det uppstod ett fel när dina integritetsval skulle sparas. Din integritet är och har alltid varit avgörande för oss. Vi använder, lagrar och behandlar dina personuppgifter för att optimera vår app (och din upplevelse) på en rad olika sätt. Vissa användningsområden för dina data är absolut nödvändiga för att få saker att fungera, andra kan du anpassa i dina inställningar. För att hjälpa oss att förbättra appens prestanda och åtgärda eventuella fel, aktivera automatiska kraschrapporter. + Skanning misslyckades. Försök igen senare Rapportera krascher Rapporter - Läs mer om vår integritetspolicy och vår cookiepolicy. - Integritets- och cookiepolicyer Integritet - Läs mer om vilka data vi samlar in om din butik och dina möjligheter att styra vilka data som delas. - Användningsspårning - Fler integritetsalternativ tillgängliga för WooCommerce.com-användare. Kolla in här för att lära dig mer. - Webbalternativ Fler integritetsalternativ Det uppstod ett fel vid uppdateringen av dina integritetsinställningar + Webbalternativ + Spårning Det uppstod ett fel vid hämtningen av dina integritetsinställningar Tillåt oss att optimera prestandan genom att samla in information om hur användare interagerar med våra mobilappar. Analys - Spårning - Vi värdesätter din integritet. Dina personuppgifter används för att optimera våra mobilappar, förbättra säkerheten, genomföra analyser och förbättra din användarupplevelse. - Systemet avslutade Woo-appen medan den kördes i bakgrunden. Du kan försöka använda den igen. Du kan inte lägga till en variabel produkt direkt. Välj en specifik variant - Skanning misslyckades. Försök igen senare + Systemet avslutade Woo-appen medan den kördes i bakgrunden. Du kan försöka använda den igen. + Vi värdesätter din integritet. Dina personuppgifter används för att optimera våra mobilappar, förbättra säkerheten, genomföra analyser och förbättra din användarupplevelse. + Läs mer om vår integritetspolicy och vår cookiepolicy. + Integritets- och cookiepolicyer + Läs mer om vilka data vi samlar in om din butik och dina möjligheter att styra vilka data som delas. + Användningsspårning Produkten med SKU %s hittades inte. Det gick inte att lägga till i beställningen - Skanning misslyckades. Försök igen senare + Fler integritetsalternativ tillgängliga för WooCommerce.com-användare. Kolla in här för att lära dig mer. Skanna streckkod + Skanning misslyckades. Försök igen senare Leverans till länder som följer EU:s tullregler kräver nu att du tydligt beskriver varje vara. Om du till exempel skickar kläder måste du ange vilken typ av kläder det är (t.ex. herrskjortor, flickvästar, pojkjackor) för att beskrivningen ska vara godtagbar. Annars kan leveranser försenas eller avbrytas i tullen. Kontakta support Detta konto kan inte avslutas eftersom det har aktiva butiker. Ett fel inträffade vid försöket att avsluta ditt konto. Det gick inte att avsluta kontot Avslutar kontot … + Rabattkod (%1$s) + -%1$s + Ta bort rabattkod från beställning Avsluta kontot permanent Bekräfta genom att skriva in ditt användarnamn innan kontot avslutas Bekräfta kontoavslut Avsluta kontot Skanna QR-koden och följ instruktionerna Skanna för att betala - Ta bort rabattkod från beställning - Rabattkod (%1$s) - -%1$s Lägg till rabattkod - Otillräckligt lager - Du måste ge en tydlig och specifik beskrivning av varje artikel. Lägg till produkter via skanner + Du måste ge en tydlig och specifik beskrivning av varje artikel. + Otillräckligt lager Avfärda Lär dig mer - Vid frakt till länder som följer EU:s tullregler måste du ange en tydlig, specifik beskrivning för varje vara. Annars kan leveranser försenas eller avbrytas i tullen. - Håll dig uppdaterad och öka butikssäkerheten. Utforska Jetpack nu. Få beställningsaviseringar och mer + Håll dig uppdaterad och öka butikssäkerheten. Utforska Jetpack nu. + Vid frakt till länder som följer EU:s tullregler måste du ange en tydlig, specifik beskrivning för varje vara. Annars kan leveranser försenas eller avbrytas i tullen. Visa eller dölj listan för butikskonfiguration Lista för butikskonfiguration Du kan få tillbaka den vid behov från Meny > Inställningar > Butik @@ -1091,37 +1127,37 @@ Language: sv_SE Aviseringar Sammansatt produkt Enhetens mediabibliotek + Tillåt Testa Tryck för att betala med automatisk återbetalning Testbetalning med Tryck för att betala - Tillåt - Uppdatera dina preferenser Inställningar - Ta emot produktrecensioner för din butik - Öka försäljningen med specialerbjudanden Visa din butik Håll dig uppdaterad - Hantera mer på admin + Uppdatera dina preferenser + Ta emot produktrecensioner för din butik + Öka försäljningen med specialerbjudanden Allmänt Inställningar - Du kan redigera paketprodukter i webbadminpanelen. %d produkter 1 produkt + Paket + Hantera mer på admin + Du kan redigera paketprodukter i webbadminpanelen. Paketprodukter Ej grupperade Inget maximum Inget minimum - Paket + Produkter + Populär + Presentkort + Presentkort + Lär dig mer om roller och behörighet + Det verkar som att din roll inte tillåter dig att installera Jetpack.\nKontakta din administratör för hjälp. Grupp om Största kvantitet Minsta kvantitet Kvantitetsregler - Presentkort - Presentkort - Produkter Senast sålda - Populär - Lär dig mer om roller och behörighet - Det verkar som att din roll inte tillåter dig att installera Jetpack.\nKontakta din administratör för hjälp. Prova Tryck för att betala Gratis provperiod Registreringsavgift @@ -1136,190 +1172,190 @@ Language: sv_SE vecka dag Anpassad - Väntar på att avslutas Löpt ut + Aktiv + Väntar på att avslutas Avslutat Pausad - Aktiv Du kan redigera produktprenumerationer i webbadminpanelen. Ingen gratis provperiod Ingen registreringsavgift Löper aldrig ut - %1$s varje %2$s %3$s - Varje %1$d %2$s - Varje %1$s Prenumeration #%1$d Prenumeration OK - Woo finns med dig hela vägen från din första försäljning till miljoner i intäkter. Se varför handlare förlitar sig på oss för att driva 3,4 miljoner onlinebutiker. Prenumeration + Prenumeration + %1$s varje %2$s %3$s + Varje %1$d %2$s + Varje %1$s + Woo finns med dig hela vägen från din första försäljning till miljoner i intäkter. Se varför handlare förlitar sig på oss för att driva 3,4 miljoner onlinebutiker. OTP-koden är felaktig. Dubbelkontrollera din information och försök igen. SMS-begäran misslyckades. Försök igen. SMS begärt, kolla dina meddelanden för att se koden. - Prenumeration Kortläsaren accepterar blipp, chipp och magnetremsa vid betalning med betal- och kreditkort. Ta emot säkra kontaktlösa betalningsmetoder direkt från din telefon. - Använd din telefon för att ta emot kort\nbetalningar Prova nu. - Dela feedback - Det går inte att logga in eftersom lösenordsskapandet i appen inte godkänts. Hämtar webbplats … + Det går inte att logga in eftersom lösenordsskapandet i appen inte godkänts. + Dela feedback + Använd din telefon för att ta emot kort\nbetalningar Prova nu. + Logga in Ett fel inträffade när webbsidan skulle hämtas Testa igen med sidan med Adminpanelen - Logga in Laddar in … %s har avslutats Din prenumeration har avslutats och du har begränsad åtkomst till alla funktionerna. %1$d dagar 1 dag Laddar in … - Konfiguration av Payments Om din butik Ett telefonnummer är obligatoriskt + Konfiguration av Payments %1$s, %2$s, %3$s, %4$s har sålts poster artikel - Det gick inte att hämta paketinformationen - Du är %1$s-prenumerant. Du har tillgång till alla våra funktioner fram till %2$s. - Din gratis provperiod har avslutats och har begränsad åtkomst till alla funktioner. Prenumerera på %1$s nu. - Du har en kostnadsfri provperiod på %1$d dagar. Din kostnadsfria provperiod löper ut om %2$s. Uppgradera för att låsa upp nya funktioner och hålla igång din butik. Prenumerationsstatus Felsökning Nuvarande: %s Rapportera prenumerationsproblem Uppgradera nu - %1$s kvar på din provperiod. - Provperioden avslutades - Din provperiod har avslutats. - Hoppsan, det uppstod några oväntade fel. Oväntat fel - Vi upptäckte att butiken redan har lanserats. - Det gick inte att lansera din butik - Det gick inte att dela butiks-URL:en Privat Din butik är live! Förhandsgranska Tillbaka till min butik - Dela URL + Sök domäner Publicera min butik + Det gick inte att hämta paketinformationen + Du är %1$s-prenumerant. Du har tillgång till alla våra funktioner fram till %2$s. + Provperioden avslutades + Din provperiod har avslutats. + Hoppsan, det uppstod några oväntade fel. + Det gick inte att lansera din butik + Det gick inte att dela butiks-URL:en + Dela URL För att lansera din butik behöver du uppgradera till vårt paket. <u>Uppgradera</u> - Sök domäner + Vi upptäckte att butiken redan har lanserats. + Du har en kostnadsfri provperiod på %1$d dagar. Din kostnadsfria provperiod löper ut om %2$s. Uppgradera för att låsa upp nya funktioner och hålla igång din butik. + %1$s kvar på din provperiod. + Din gratis provperiod har avslutats och har begränsad åtkomst till alla funktioner. Prenumerera på %1$s nu. + Något gick fel. Försök igen senare. Inloggning misslyckades med statuskod %1$s Det gick inte att logga in, eftersom vi inte kan identifiera admin-URL:en för din butik Det gick inte att logga in, eftersom vi inte kan identifiera inloggnings-URL:en för din butik Inloggningen misslyckades med ett oväntat svar från din webbplats. Vi jobbar på att lösa det här problemet. - Något gick fel. Försök igen senare. Det finns krav som inväntar granskning i ditt konto. Slutför dessa krav för att fortsätta ta emot personliga betalningar. Betygsätt gärna din analysupplevelse Gillar du analysen? Vi har jobbat på att göra det möjligt att visa viktig butiksinformation från din enhet. Skulle den kunna vara bättre? Hjälp oss att förbättra den här funktionen genom att dela din feedback med oss Se din statistik, dina intäkter med mera från din enhet. Ett fel uppstod vid hämtningen av din webbplats. Försök igen. - Vi kan tyvärr inte skapa supportförfrågningar för tillfället. Försök igen senare. Något gick fel Jag förstår! + Vi kan tyvärr inte skapa supportförfrågningar för tillfället. Försök igen senare. Din supportförfrågan har landat säkert i vår inkorg. Vi kommer att svara via e-post så snart vi kan. - Förfrågan skickad. Vänta … - Skickar din förfrågan + Jag behöver hjälp med + Ämne + Supportförfrågan + Dela feedback + Meddelande + Skriv något + Visa alla (%1$d) + Ge dina kunder ett enkelt och bekvämt sätt att betala! + Få betalt Annan utökning/tillägg WooCommerce-tillägg + Förfrågan skickad. + Skickar din förfrågan WooCommerce-betalningar Kortläsare/personliga betalningar Mobilapp - Skriv något - Meddelande Skicka supportförfrågan - Ämne Meddela oss din webbplatsadress (URL) och berätta så mycket du kan om problemet, så kommer vi att kontakta dig snart. Låt oss ordna detta - Jag behöver hjälp med - Supportförfrågan - Dela feedback Onboarding, minimerad lista Onboarding, fullskärm - Visa alla (%1$d) %1$d av %2$d uppgifter har slutförts - Ge dina kunder ett enkelt och bekvämt sätt att betala! - Få betalt Vi använder den här informationen för att snabbare kunna konfigurera dina frakt-, moms- och betalningsinställningar. - Berätta mer om din butik - Vi har precis skickat en magisk länk till e-postadressen för ditt konto Logga in för att fortsätta - Få åtkomst till alla dina WooCommerce-butiker. - Flera butiker - Hämtar Jetpack-status + Berätta mer om din butik Något blev fel. Försök igen senare. Prova en betalning - Ta emot kortbetalningar\nmed din telefon - Tryck för att betala + Flera butiker + Hämtar Jetpack-status + Få åtkomst till alla dina WooCommerce-butiker. + Vi har precis skickat en magisk länk till e-postadressen för ditt konto + Välj land + Välj delstat ÅTGÄRDER Ett fel uppstod under domänregistrering - Välj delstat - Välj land + Ta emot kortbetalningar\nmed din telefon + Tryck för att betala Registrerar domännamn … - Registrera domän - Postnummer - Delstat (Inte tillgänglig) - Delstat - Ort - Adress 2 - Adress - Land - Landskod Telefon - Organisation (valfritt) + Landskod + Land + Adress + Adress 2 + Ort + Delstat + Delstat (Inte tillgänglig) + Postnummer + Registrera domän För din bekvämlighet har vi förfyllt din WordPress.com\n kontaktinformation. Granska det för att vara säker på att det är rätt information du vill använda för denna domän. - Kontaktinformation för domän - Registrera publikt - Registrera privat med integritetsskydd - Ange en giltig %s - I och med att du registrerar denna domän accepterar du våra %1$savtalsvillkor%2$s + Organisation (valfritt) Domänägare måste uppge kontaktinformation i en publik databas som omfattar alla domäner. Med integritetsskydd publicerar vi våra uppgifter istället för dina, och vidarebefordrar sedan privat eventuella meddelanden till dig. + I och med att du registrerar denna domän accepterar du våra %1$savtalsvillkor%2$s + Ange en giltig %s + Registrera privat med integritetsskydd + Registrera publikt + Kontaktinformation för domän Integritetsskydd Endast butiksadministratörer kan komma åt domäninställningar - Eller fortsätt med magisk länk - Ange lösenordet för ditt WordPress.com-konto för att installera Jetpack - Ange lösenordet för ditt WordPress.com-konto för att ansluta till Jetpack Logga in på ditt WordPress.com-konto för att installera Jetpack Logga in på ditt WordPress.com-konto för att ansluta Jetpack - Du hittar domäninställningarna via Inställningar > Domäner + Ange lösenordet för ditt WordPress.com-konto för att installera Jetpack + Ange lösenordet för ditt WordPress.com-konto för att ansluta till Jetpack + Eller fortsätt med magisk länk + Gratis första året Din webbplatsadress håller på att konfigureras. Det kan dröja upp till 30 minuter innan din domän börjar fungera. Grattis till dina köp - Gratis första året + Du hittar domäninställningarna via Inställningar > Domäner Är du säker på att du vill logga ut från ditt konto? Kan inte ladda webbplatsdomäner - %1$d/%2$d har slutförts - Få en anpassad URL för din butik. Anpassa din domän Publicera din webbplats till världen när du vill! Lansera din butik + %1$d/%2$d har slutförts + Få en anpassad URL för din butik. Börja sälja genom att lägga till produkter eller tjänster i din butik. Lägg till din första produkt Konfigurera din butik - Något gick fel med appkonfigurationen. Kontakta supporten för mer information + Välj domän Din enhet stöds inte. Kontakta support för mer detaljer + Något gick fel med appkonfigurationen. Kontakta supporten för mer information Appen kunde inte aktivera kortläsaren, eftersom NFC-chippet är inaktiverat Transaktionen avbröts Den köpta domänen kommer att omdirigera användare till - Välj domän Lägg till en domän - Domänerna för din webbplats + Din gratis butiksadress Primär webbplatsadress - <a href=\'\'><u>Lär dig mer</u></a> om domäner och hur man vidtar domänrelaterade åtgärder. Sök efter en domän Den köpta domänen kommer omdirigera användare till din primära adress. Gör anspråk på domän + <a href=\'\'><u>Lär dig mer</u></a> om domäner och hur man vidtar domänrelaterade åtgärder. + Domänerna för din webbplats Ditt paket inkluderar en gratis domännamnsregistrering i ett år. Gör anspråk på din gratisdomän - Din gratis butiksadress Domäner Visa inte igen Påminn mig senare - Inga problem! Du kan alltid gå till Inställningar i menyn för att skicka feedback. Dela feedback Dela feedback - Berätta för oss om din upplevelse av personliga betalningar. Berätta vad du tycker + Inga problem! Du kan alltid gå till Inställningar i menyn för att skicka feedback. + Berätta för oss om din upplevelse av personliga betalningar. Betygsätt din första upplevelse av personliga betalningar. Gillar du att använda personliga betalningar? Dela din egen upplevelse av att ta emot personliga betalningar. @@ -1330,106 +1366,105 @@ Language: sv_SE Det går inte att duplicera produkten Duplicera Förbereder för betalning + Domän Det går snabbt - Förbereder inbyggd läsare … Den inbyggda läsaren är redo - Kortläsare Tryck för att betala Omvandlingsfrekvens Sessioner Inga sessioner denna period Jämfört med - Domän + Kortläsare + Förbereder inbyggd läsare … Vad är applikationslösenord? Det verkar som att funktionen Applikationslösenord är inaktiverad på din webbplats %1$s.\n Aktivera den om du vill använda WooCommerce-appen. Öppna installationssida - Det uppstod ett fel när svaret skulle skickas Svar skickat! + Det uppstod ett fel när svaret skulle skickas Svara - Välj alla Uppdatera pris Uppdatera status Status uppdaterad! Uppdatera status Pris uppdaterat! Uppdatera ordinarie pris + Välj alla Alla variationer har redan genererats. Inga variationer att generera Välj flera Inga tillgängliga domäner för denna sökning + Generera alla varianter? Genererar varianter Detta kommer skapa en ny variation för varje möjlig kombination av variationsattribut (%1$d variationer). - Generera alla varianter? Skapande stöds för närvarande för högst %1$d variationer. Att generera variationer för den här produkten skulle skapa %2$d variationer. Gräns för generering överskriden Skapar variationer för alla kombinationer av dina attribut. - Generera alla variationer Skapa en ny variation. Ange manuellt vilka attribut som tillhör den variabla produkten. Lägg till ny variation Lägg till variation + Generera alla variationer + Försök att ansluta igen för att komma åt din butik. Lämna utan att ansluta Fortsätt ansluta - Försök att ansluta igen för att komma åt din butik. Jetpack är installerat men inte anslutet. Du har inte behörighet att ansluta Jetpack till den här butiken Kontakta din butikshanterare eller -administratör för att få hjälp. + Fel + Felkod %1$s + Din butik <b>%1$s</b> är nu ansluten till Jetpack. + Vänta medan vi ansluter din butik <b>%1$s</b> med Jetpack. + Ansluter Jetpack + Installerar Jetpack + Allt klart + Validerar + Anslut butik till Jetpack + Aktiverar + Installerar Jetpack Avbryt installation Försök auktorisera igen Försök att aktivera igen Försök installera igen Skaffa support Försök igen och kontakta supporten om detta fel fortsätter. - Ett fel uppstod vid kommunikationen med din webbplats. Du har inte behörighet att hantera tillägg på denna butik + Anslut Jetpack + Gå till butik + Ett fel uppstod vid kommunikationen med din webbplats. Det gick inte att auktorisera anslutningen till Jetpack Det gick inte att aktivera Jetpack Det gick inte att installera Jetpack - Anslut Jetpack - Gå till butik - Fel - Felkod %1$s - Din butik <b>%1$s</b> är nu ansluten till Jetpack. - Vänta medan vi ansluter din butik <b>%1$s</b> med Jetpack. Installera Jetpack Jetpack har anslutits - Ansluter Jetpack - Installerar Jetpack - Allt klart Ansluten - Validerar - Anslut butik till Jetpack - Aktiverar - Installerar Jetpack Logga in på <b>%1$s</b> med autentiseringsuppgifterna för din butik för att ansluta Jetpack. Logga in på <b>%1$s</b> med autentiseringsuppgifterna för din butik för att installera Jetpack. - Ha autentiseringsuppgifterna för din butik redo. + Skapa din första butik Anslut din butik till Jetpack för att komma åt den på denna app. + Ha autentiseringsuppgifterna för din butik redo. Installera det kostnadsfria Jetpack-tillägget för att komma åt din butik med den här appen. Kom igång och börja sälj snabbt med en vacker onlinebutik. - Skapa din första butik - Slumpmässigt Aldrig Alltid + Slumpmässigt Uppdatera simulerad läsarnyckel Uppdatera simulerad kortläsare Anslut Jetpack Anslut butik - Det är här människor kommer hitta dig på Internet. Oroa dig inte, du kan ändra detta senare. Besökare + Det är här människor kommer hitta dig på Internet. Oroa dig inte, du kan ändra detta senare. Eller logga in med lösenord - Den simulerade kortläsaren har inaktiverats Simulerad läsarnyckel + Nuvarande lagerantal är %d + Den simulerade kortläsaren har inaktiverats Lagerkvantiteten har uppdaterats Den aktuella lagerkvantiteten är blandad - Nuvarande lagerantal är %d Uppdaterar lagerkvantiteten Lagerkvantiteten kommer att uppdateras för %d variationer Lagersaldo + Skapa en ny butik + Anslut en befintligt butik Sök filtrerade produkter Sök filtrerade beställningar - Anslut en befintligt butik - Skapa en ny butik - Nettoförsäljning: %1$s Sålda artiklar Produkter Produkter @@ -1444,104 +1479,102 @@ Language: sv_SE Inga intäkter denna period Intäkt %1$s – %2$s - Vi kunde inte skapa ett konto med de angivna autentiseringsuppgifterna. Prova med en annan e-postadress. - Ditt lösenord uppfyller inte våra säkerhetsriktlinjer. Försök med ett mer komplext lösenord. Ditt lösenord är för kort. Välj ett lösenord som har minst 6 tecken. Ange en giltig e-postadress. Ett konto med denna e-post finns redan. + Ditt lösenord uppfyller inte våra säkerhetsriktlinjer. Försök med ett mer komplext lösenord. + Nettoförsäljning: %1$s + Vi kunde inte skapa ett konto med de angivna autentiseringsuppgifterna. Prova med en annan e-postadress. Försök med en annan adress Anpassat datumintervall Anpassat - Vad är WordPress.com? Skapar nytt konto Välj ett lösenord Din e-postadress Kom igång \npå några minuter Genom att klicka på knappen Anslut Jetpack godkänner du våra <a href=\'terms\'>användarvillkor</a> och samtycker till att <a href=\'sync\'>dela information</a> med WordPress.com. - Aktivera simulerad kortläsare - Kontakta webbplatsens ägare för en inbjudan till webbplatsen som butikschef eller administratör för att använda appen. + Vad är WordPress.com? Ansluter till en WordPress.com-webbplats Anslut till webbplatsen Anslut Jetpack till ditt konto + Kontakta webbplatsens ägare för en inbjudan till webbplatsen som butikschef eller administratör för att använda appen. + Aktivera simulerad kortläsare + Visa lösenord + Dölj lösenord Redigera behörigheter För att använda den här funktionen, tillåt att din kamera används. Kameraåtkomst krävs Kamerastreckkodsskanner Utvecklaralternativ 2FA stöds inte för webbplatser som drivs på egen server. Använd ett applösenord. - Visa lösenord - Dölj lösenord Per den %1$s Det gick inte att ladda data - WooCommerce-statistik idag Dagens butiksstatistik Butiksanalys inte tillgänglig! Uppgradera till den senaste versionen av WooCommerce för att visa din butiksanalys. Ditt nätverk är inte tillgängligt.\nKontrollera din data eller WiFi-anslutning. Logga in på WooCommerce-appen - Det gick inte att hämta anslutningsdata … + WooCommerce-statistik idag Verifierar Jetpack-anslutning … + Det gick inte att hämta anslutningsdata … Kan inte verifiera din Jetpack-anslutning. Försök igen. Webbplatsen %1$s har för närvarande ett WordPress.com-paket som inte stöder installation av tillägg. Uppgradera ditt paket för att använda WooCommerce. Det verkar som att ditt konto inte är anslutet till Jetpack för %1$s KORTLÄSARE BETALNINGSALTERNATIV + Vi kunde inte ansluta till din webbplats. Kontakta supporten för att felsöka problemet. Kassaalternativet Betala personligen gör det möjligt att ta emot betalningar för webbplatsbeställningar vid upphämtning eller leverans. <a href=\'\'>Läs mer</a> Betala personligen - Vi kunde inte ansluta till din webbplats. Kontakta supporten för att felsöka problemet. Anslutningsfel Det finns ett problem som kräver din uppmärksamhet. <a href=\'\'>Ta en titt på detta</a> Försök med en annan adress Det gick inte att aktivera Postförskott. Försök igen senare. Aktivera Betala personligen - <a href=\'\'>Läs mer</a> om Personliga betalningar - Är WooCommerce nytt för dig? Ett fel uppstod, kontakta support Ange en webbplatsadress + <a href=\'\'>Läs mer</a> om Personliga betalningar + Är WooCommerce nytt för dig? Få en inloggningslänk via e-post Kommer du inte ihåg ditt lösenord? Vi har noterat att du inte har slutfört installationen av Personliga betalningar. <a href=\'\'>Fortsätt installationen</a> Betalningar Jag förstår! - Now you can quickly access In-Person Payments and other features with ease Betalningar från menyfliken - Din e-post används inte med ett WordPress.com-konto. Andra webbplatser Logga in med din butiksadress WC-admin - Vi har precis skickat en magisk länk till + Now you can quickly access In-Person Payments and other features with ease + Din e-post används inte med ett WordPress.com-konto. Kontrollera din e-post på denna enhet! Använd lösenord för att logga in Logga in med magisk länk - Vi har precis skickat en magisk länk till din e-postadress. Tryck på länken i e-postmeddelandet för att logga in. Logga in med dina webbplatsuppgifter - Ge dina kunder användbara och relevanta produktrekommendationer genom att lägga till merförsäljning och korsförsäljning - Öka din försäljning med länkade produkter - Börja sälja personligen på under 20 minuter med vår kortläsare. - Det gick inte att uppdatera beställning #%1$d - Beställning #%1$d har markerats som slutförd - Markera\nslutförd + Vi har precis skickat en magisk länk till din e-postadress. Tryck på länken i e-postmeddelandet för att logga in. + Vi har precis skickat en magisk länk till Installera WooCommerce - Det verkar som att %1$s inte är en WooCommerce-webbplats. - Växla mellan flera olika butiker Hantera mina beställningar Skapa eller uppdatera mina produkter - Kolla min analys - Försöker skapa en butik - Utforskar bara - Vad för dig till WooCommerce? Tips Ställ in nu + Öka din försäljning med länkade produkter + Börja sälja personligen på under 20 minuter med vår kortläsare. + Vad för dig till WooCommerce? + Utforskar bara + Försöker skapa en butik + Kolla min analys + Växla mellan flera olika butiker + Det verkar som att %1$s inte är en WooCommerce-webbplats. + Markera\nslutförd + Beställning #%1$d har markerats som slutförd + Det gick inte att uppdatera beställning #%1$d + Ge dina kunder användbara och relevanta produktrekommendationer genom att lägga till merförsäljning och korsförsäljning Då sätter vi igång! Logga in med WordPress.com Kontakta supporten - Logga in med ditt WordPress.com-konto Skaffa lite hjälp! Har du problem med att logga in? - Artikelnr Alla produkter VISA INTE IGEN PÅMINN MIG SENARE - Inga problem! Du kan alltid komma igång med In-Person Payments via Inställningar. Personliga betalningar Köp kortläsare Ta emot betalningar enkelt @@ -1549,27 +1582,29 @@ Language: sv_SE Avfärda Visa anpassade fält Anpassade fält - Det gick inte att spara ändringar - Detta kommer att markera denna beställning som betald om du fått betalning utanför WooCommerce Installera Jetpack - Vi gör det möjligt för dig att bearbeta betalningar på ett enkelt och smidigt sätt Du kan hantera dem snabbt och enkelt Vi vet att det är viktigt för ditt företag + Det gick inte att spara ändringar + Detta kommer att markera denna beställning som betald om du fått betalning utanför WooCommerce + Artikelnr + Inga problem! Du kan alltid komma igång med In-Person Payments via Inställningar. + Vi gör det möjligt för dig att bearbeta betalningar på ett enkelt och smidigt sätt Är WooCommerce nytt för dig? - Ny beställning för 50 USD i din WooCommerce-butik + Logga in med ditt WordPress.com-konto Du har en ny beställning! 🎉 + Ny beställning för 50 USD i din WooCommerce-butik detaljerna Redigera alla %1$s genom att gå igenom beställningen i din WooCommerce-butiksadmin %1$s är ofullständiga + Fortsätt söka + Inväntar betalning Dela systemstatusrapport Kopiera systemstatusrapport till urklipp - Fortsätt söka - Personlig betalning för beställning #%1$s för %2$s blog_id %3$s. Ändra betalningsleverantör Återbetalat: %1$s - Inväntar betalning + Personlig betalning för beställning #%1$s för %2$s blog_id %3$s. Fortsätt med installation - Saker du bör veta innan du installerar Installera utökning WooCommerce Shipping Rensa filter @@ -1578,30 +1613,26 @@ Language: sv_SE Det gick inte att ladda in produkter Sök produkter Filter (%d) + Saker du bör veta innan du installerar Vissa e-postadresser är ogiltiga. Åtgärda den angivna e-postadressen/de angivna e-postadresserna. Lista över tillåtna fakturerings-e-postadresser att kontrollera mot när en beställning görs. Separera e-postadresser med kommatecken. Du kan också använda en asterisk (*) för att matcha delar av en e-postadress. Exempelvis skulle \"*gmail.com\" matcha alla gmail-adresser. - Inga produkter matchar de valda filtren ” Bekräfta betalningsmetod Stripe WooCommerce Payments - Personliga betalningar kan behandlas via båda dessa betalningsleverantörer. Vilken leverantör vill du använda? + Inga kunder hittades. Välj din betalningsleverantör låst - För att redigera produkter eller betalningsinformation, ändra statusen till Inväntar betalning. Delar av denna beställning är för närvarande inte redigerbara + Inga produkter matchar de valda filtren ” + Personliga betalningar kan behandlas via båda dessa betalningsleverantörer. Vilken leverantör vill du använda? + För att redigera produkter eller betalningsinformation, ändra statusen till Inväntar betalning. Sök efter kunder - Inga kunder hittades. Inte nu Lägg till utökningar till butik Vad är WooCommerce Shipping? Kom åt rabatterade fraktavgifter. För närvarande endast tillgängligt med DHL och USPS, men fler alternativ kommer snart. - Rabatterade avgifter - Hämta en beställning och sedan är det bara att betala, skriva ut, paketera och skicka. Skriv ut från din telefon - Du behöver inte undra var den frimärkshäftet tog vägen. - Köp porto när du behöver det Spara tid och pengar - Fullfölj dina beställningar med WooCommerce Shipping Visa detaljer Välj variant %s Exkludera produktkategorier @@ -1610,13 +1641,10 @@ Language: sv_SE Inga begränsningar Tillåtna e-postadresser Obegränsat - Samtliga kvalificerande artiklar Obegränsat Ingen Redigera produktkategorier (%1$d) Välj produktkategorier - För närvarande stöds massuppdatering för maximalt 100 varianter. - Gräns för massuppdatering har överskridits Uppdatera ordinarie priser Uppdaterar reapriser Uppdaterade reapriser. @@ -1634,9 +1662,14 @@ Language: sv_SE Massuppdatera OK Massuppdatera … - Hämtar varianter … - Det gick inte att söka efter produktkategorier - Det gick inte att läsa in produktkategorier + Du behöver inte undra var den frimärkshäftet tog vägen. + Köp porto när du behöver det + För närvarande stöds massuppdatering för maximalt 100 varianter. + Gräns för massuppdatering har överskridits + Hämta en beställning och sedan är det bara att betala, skriva ut, paketera och skicka. + Fullfölj dina beställningar med WooCommerce Shipping + Rabatterade avgifter + Samtliga kvalificerande artiklar Sök kategorier Rensa val Klicka för att avmarkera @@ -1644,15 +1677,17 @@ Language: sv_SE Välj %1$d kategorier Inga produktkategorier hittades Välj kategorier - Avfärda banner för att installera WC Shipping + Behöver du en fraktetikett? Skaffa WooCommerce Shipping Skriv ut etiketter från din telefon, med WooCommerce Shipping. - Behöver du en fraktetikett? - Ändra produktantalet från %1$d till %2$d + Hämtar varianter … + Det gick inte att söka efter produktkategorier + Det gick inte att läsa in produktkategorier + Avfärda banner för att installera WC Shipping Uppdatera ordinarie pris Uppdatera reapris + Ändra produktantalet från %1$d till %2$d Vi stöder inte WooCommerce Stripe-utökningen i %1$s - Filter Rensa val Välj %d produkt Välj %d produkter @@ -1661,32 +1696,31 @@ Language: sv_SE Redigera produkter (%d) Alla produkter Välj produkter - Aktivera det här alternativet om rabattkoden inte ska gå att tillämpa på reavaror. Per-artikel-rabattkoder fungerar bara om varan inte är en reavara. Per-varukorg-rabattkoder fungerar bara om varorna i varukorgen inte är reavaror. Exkludera artiklar på rea + Aktivera det här alternativet om rabattkoden inte ska gå att tillämpa på reavaror. Per-artikel-rabattkoder fungerar bara om varan inte är en reavara. Per-varukorg-rabattkoder fungerar bara om varorna i varukorgen inte är reavaror. Aktivera det här alternativet om rabattkoden inte ska kunna användas tillsammans med andra rabattkoder. + Filter + Vänta … + Sparar rabattkod + Rabattkod uppdaterad + Användningsbegränsningar + Ingen + Tillämpa denna rabattkod på + Välj butik att ansluta + %s i lager + Det gick inte att hämta butiker + Inkludera gratis frakt? + Rensa Kan inte kombineras Användningsbegränsning per kund Begränsa användningen till X artiklar Användningsbegränsning per rabattkod Maximalt beställningsbelopp (%1$s) Minsta beställningsbelopp (%1$s) - Vänta … - Sparar rabattkod Det gick inte att uppdatera rabattkoden - Rabattkod uppdaterad - Användningsbegränsningar Användningsinformation - Inkludera gratis frakt? - Rensa - Ingen - Tillämpa denna rabattkod på Det gick inte att söka efter rabattkoder Det gick inte att hämta rabattkoder - Det gick inte att hämta butiker - Välj butik att ansluta - %s i lager - Lägg till beskrivningen för rabattkoden. - Rabattkodsbeskrivning Redigera beskrivning Lägg till beskrivning (valfritt) Rabattkodens utgångsdatum @@ -1697,93 +1731,90 @@ Language: sv_SE Ställ in beloppet på rabatten du vill erbjuda. Ställ in procenten för rabatten du vill erbjuda. Belopp (%1$s) - Rabattkodsinformation Redigera %1$s Redigera rabattkod Kan inte uppdatera produkt + Lägg till beskrivningen för rabattkoden. + Rabattkodsbeskrivning + Rabattkodsinformation Något gick fel när återbetalningen skulle tillämpas Tillämpar återbetalning för beställning - Kortläsarbild + Kopierat till urklipp Beräknat belopp: %s Beräkna som procent - Kopierat till urklipp + Kortläsarbild + Kan användas %1$d gång + Kan användas %1$d gånger + Rabattkod borttagen + Misslyckades att ta bort rabattkod + Är du säker på att du vill ta bort denna rabattkod? + Ta bort rabattkod + Avfärda alla + Inkorg Begränsad till kunder med följande e-postadresser: %1$s Gäller inte reavaror Tillåter gratis frakt Kan inte kombineras Begränsad till %1$d artiklar i varukorgen Begränsad till %1$d artiklar i varukorgen - Kan användas %1$d gång - Kan användas %1$d gånger %1$d användning per användare %1$d användningar per användare - Rabattkod borttagen - Misslyckades att ta bort rabattkod - Är du säker på att du vill ta bort denna rabattkod? - Ta bort rabattkod Det gick inte att synkronisera inkorgen - Avfärda alla - Inkorg Kortläsarmanualer Tryck eller infoga för att återbetala Beställningen är redan återbetald - Återbetalning avbruten OK + Återbetalning avbruten + Denna återbetalning kunde inte behandlas + Kortet stöder inte denna typ av återbetalning + Prova ett annat sätt att återbetala Systemtestkort är inte tillåtna för återbetalningen Återbetalningsbeloppet är inte tillåtet för det aktuella kortet Återbetalningen avvisades på grund av otillräckliga medel En identisk återbetalning skickades nyligen - Kortet stöder inte denna typ av återbetalning Återbetalningen avvisades av ospecificerad anledning - Prova ett annat sätt att återbetala Återbetalningen avvisades av okänd anledning - Denna återbetalning kunde inte behandlas + Kopiera Återbetalning lyckades + Återbetalning misslyckades Behandlar återbetalning Återbetala betalning - Återbetalning misslyckades Förbereder återbetalning av betalning - Kopiera Sök rabattkoder + Rabattkod + Löper ut %1$s + Anpassad rabatt (%1$s) + Fast produktrabatt + Fast varukorgsrabatt + Dela rabattkod + Kopiera rabattkod + Rabattkod kopierad till urklipp. Det gick inte att generera meddelandet för delning av rabattkoden Det gick inte att dela rabattkoden. Tillämpa %1$s rabatt på utvalda produkter med kampanjkoden %2$s Tillämpa %1$s rabatt på alla produkter med kampanjkoden %2$s Det gick inte att kopiera rabattkoden till urklipp. - Rabattkod kopierad till urklipp. - Rabattkod Det gick inte att ladda rabattkodssammanfattningen - Löper ut %1$s %1$s rabatt på %2$s - Anpassad rabatt (%1$s) - Fast produktrabatt - Fast varukorgsrabatt Procentuell rabatt Det gick inte att ladda rabattkodsprestanda - Dela rabattkod - Kopiera rabattkod Tack för din feedback! + Dela betalningslänk Kortläsarbetalningar kräver exakt platsbehörighet Åtkomst till plats krävs Kassa – %s - Dela betalningslänk Belopp Belopp Rabatterade beställningar - Prestanda - Maximalt beställningsbelopp på %s - Minsta beställningsbelopp på %s - Rabattkodssammanfattning - Visa rabattkodssammanfattning - Vi har arbetat med att göra det möjligt att visa och redigera rabattkoder från din enhet! Visa och redigera rabattkoder Inga rabattkoder hittades - %1$s exkl. %2$s - %1$s och %2$s + Rabattkoder + %d kategorier + %d kategori + Visa rabattkodssammanfattning allt Har löpt ut Aktiva - Rabattkoder Skapades den %s För %d dagar sedan För en dag sedan @@ -1791,12 +1822,17 @@ Language: sv_SE För en timme sedan För %d minuter sedan För en stund sedan - %d kategorier - %d kategori \u2022 inga godkända recensioner \u2022 en godkänd recension \u2022 %d godkända recensioner %1$s (%2$s%%) + Prestanda + Maximalt beställningsbelopp på %s + Minsta beställningsbelopp på %s + Rabattkodssammanfattning + Vi har arbetat med att göra det möjligt att visa och redigera rabattkoder från din enhet! + %1$s och %2$s + %1$s exkl. %2$s Vi har jobbat på att göra det möjligt att skapa beställningar från din enhet. Du kan prova den här funktionen genom att trycka på \"+\"-knappen Kom tillbaka snart för fler tips och insikter om hur du får din butik att växa Grattis, du har läst allt! @@ -1809,12 +1845,12 @@ Language: sv_SE Anrop med XML-RPC verkar blockerade på denna webbplats (felkod 401). Om försöket att logga in misslyckas tryck på hjälpikonen för att se vanliga frågor. Kunde inte läsa WordPress-webbplatsen på denna URL. Tryck på hjälpikonen för att se vanliga frågor. Tjänsten för XML-RPC är inaktiverad på denna webbplats. + Procent (%) Använd en e-postadress som inte är kopplad till Automattic för att skicka in ett supportärende Vi stöder inte Stripe-konton som är registrerade i %1$s - Vi stöder inte WooCommerce Payments-utökning i %1$s Tryck på strömknappen på din läsare Ett kvitto har skickats till <strong>%s</strong> - Procent (%) + Vi stöder inte WooCommerce Payments-utökning i %1$s Ta bort avgift från beställning Ta bort frakt från beställning Frakt @@ -1825,11 +1861,9 @@ Language: sv_SE Avgifter Kunddetaljer Lägg till avgift - Redigera kundanteckning Redigera kunddetaljer Redigera beställningsstatus - Beställningen med enkel betalning gick inte att uppdatera - Beställningen med enkel betalning gick inte att skapa + Redigera kundanteckning Användarens profilbild Recensioner Visa butik @@ -1837,29 +1871,31 @@ Language: sv_SE Analyser Betalningar WooCommerce-admin + Beställningen med enkel betalning gick inte att uppdatera + Beställningen med enkel betalning gick inte att skapa Meny Uppdatera efter uppdatering Hantera tillägg WooCommerce Payments + eller WooCommerce Stripe Gateway Personliga betalningar fungerar endast med ett av följande tillägg aktiverat. Kontakta en webbplatsadministratör för att inaktivera ett av dessa tillägg och fortsätta: Personliga betalningar fungerar endast med ett av följande tillägg aktiverat. Inaktivera ett av dessa tillägg för att fortsätta. Konflikt mellan betalningstillägg upptäckt Momser totalt - eller Installera Jetpack - Personliga betalningar är för närvarande inte tillgängliga - Beställning skapad - Misslyckades att skapa beställning Vänta … Skapar din beställning + Skapa + Beställning skapad + Misslyckades att skapa beställning + Personliga betalningar är för närvarande inte tillgängliga Beställningens totalsumma Produktbelopp Betalning Nettoförsäljning: %s Sålda artiklar Konvertering - Skapa App-ikon Ikon för tillbaka Logga för Automattic @@ -1890,58 +1926,69 @@ Language: sv_SE Kontakta supporten Aktivera Installera - %s Jetpack i WP Admin aktivera installera - Alternativt kan du %s Jetpack i WP-admin. + %s Jetpack i WP Admin Försök igen. ansluter aktivering installation + WooCommerce + Alternativt kan du %s Jetpack i WP-admin. Något gick fel under %s Hej! Här är en länk för att ladda ner WooCommerce-appen. Jag tycker att den är jättebra och tänkte att du också skulle gilla den. %1$s - WooCommerce - product_card_detail - product_card_%1$s - review_card_detail review_card_%1$s + review_card_detail + product_card_%1$s + product_card_detail Uppdatera Stripe - Du är nästan där! Slutför konfigurationen av Stripe för att börja ta emot kortbetalningar. - Slutför konfigurationen av Stripe i adminpanelen för din butik - Återbetala avgifter - Avgiftsåterbetalning Välj variant Ta bort produkt från beställning Lägg till rabatt Produkt - Lägg till en annan leveransadress + Du är nästan där! Slutför konfigurationen av Stripe för att börja ta emot kortbetalningar. + Slutför konfigurationen av Stripe i adminpanelen för din butik + Återbetala avgifter + Avgiftsåterbetalning I lager %s i lager - Lägg till produkter Produkter - Lägg till kunddetaljer Kund Markera som betald - Detta kommer att skapa din beställning och markera den som slutförd om du har mottagit betalning utanför WooCommerce Markera som betald? Välj din betalningsmetod - Moms beräknas automatiskt baserat på din butiksadress Moms (%s&nbsp;%%) - Ta emot betalning %s - Debitera moms + Lägg till en annan leveransadress + Detta kommer att skapa din beställning och markera den som slutförd om du har mottagit betalning utanför WooCommerce + Moms beräknas automatiskt baserat på din butiksadress + Lägg till kunddetaljer + Lägg till produkter Anpassat belopp Ange e-post - Enkel betalning - order_card_detail - order_card_%1$s + Moms Kontant Kort - Moms + Ta emot betalning %s + Debitera moms + Enkel betalning + order_card_%1$s + order_card_detail E-post + Uppdatera efter uppdatering Lägg till anteckning Kundmeddelande - Uppdatera efter uppdatering En föråldrad version av utökningen WooCommerce Stripe Gateway är installerad för din butik. Uppdatera den för att ta emot personliga betalningar. + Ny beställning + Förra veckan + År till datum + Kvartal till datum + Månad till datum + Vecka till datum + Förra året + Förra kvartalet + Förra månaden + Kortet har löpt ut + %1$s (%2$s) Betalningen avvisades av okänd anledning Ett live-kort användes på en webbplats i testläge Systemtestkort är inte tillåtna för betalning @@ -1950,7 +1997,6 @@ Language: sv_SE Betalningsbeloppet är inte tillåtet för det aktuella kortet Betalningen avvisades på grund av otillräckliga medel Transaktionens postnummer och kortets postnummer matchar inte - Kortet har löpt ut En identisk transaktion skickades nyligen Kortet stöder inte denna valuta Kortet stöder inte denna typ av köp @@ -1958,82 +2004,71 @@ Language: sv_SE Betalningen avvisades av ospecificerad anledning Prova en annan betalningsmetod Det kan fungera att prova igen - Ny beställning Väljare för datumintervallsfilter kontra föregående period (%1$s) - %1$s (%2$s) - År till datum - Kvartal till datum - Månad till datum - Vecka till datum - Förra året - Förra kvartalet - Förra månaden - Förra veckan - Enkla betalningar Visa utökningar Vi kunde inte hitta några beställningar Öppna inställningar + Enkla betalningar Saknar nödvändig behörighet för enheter i närheten - Filtrera länder - Filtrera stater - Status Slutdatum Startdatum Välj datum Anpassat intervall - Skapa en beställning med minimalt med information - Enkel betalning Skapa en ny manuell beställning Skapa beställning Skapa beställning Ange belopp + Filtrera länder + Filtrera stater + Status + Skapa en beställning med minimalt med information + Enkel betalning Ta emot betalning Enkel betalning - Skapa beställningar från din enhet! Analys - Allt klart + Skapa beställningar från din enhet! Ansluter din butik Aktiverar Installerar Jetpack - Vänta medan vi ansluter %s till Jetpack. - Installerar\nJetpack + Installera Jetpack din webbplats + Installerar\nJetpack + Läsare är ansluten + Allt klart + Vänta medan vi ansluter %s till Jetpack. Installera det kostnadsfria Jetpack-tillägget till <strong>%s</strong> för den bästa mobilupplevelsen. - Installera Jetpack Produktrecensionerna kunde inte hämtas Läsaren är frånkopplad - Läsare är ansluten Att avbryta en pågående programvaruuppdatering är inte att rekommendera. Om du avbryter blockeras din läsaranslutning. Uppdateringen av läsarprogramvaran misslyckades, eftersom läsarens batteri inte är tillräckligt laddat. Ladda läsaren till över 50 %% innan du försöker igen. - Uppdateringen av läsarprogramvaran misslyckades, eftersom läsarens batteri endast är laddat till %1$s%%. Ladda läsaren till över 50 %% innan du försöker igen. Ladda läsare - Din kortläsares programvara behöver uppdateras för att fungera korrekt - Ange ett giltigt postnummer i dina butiksinställningar och försök igen - Postnumret i butiksadressen är ogiltigt - Ange adress - Ange din butiksadress för att fortsätta + Uppdateringen av läsarprogramvaran misslyckades, eftersom läsarens batteri endast är laddat till %1$s%%. Ladda läsaren till över 50 %% innan du försöker igen. + %1$s (%2$d) + Alla + Filtrerade beställningar + Alla beställningar Kontrollera din mobila enhet - Adressen kan inte uppdateras med en tom e-postadress. Kontrollera att du kör den senaste versionen av WooCommerce. Senaste 30 dagarna Senaste 7 dagarna Senaste 2 dagarna Idag - %1$s (%2$d) - Alla - Filtrerade beställningar - Alla beställningar + Ange adress + Din kortläsares programvara behöver uppdateras för att fungera korrekt + Ange ett giltigt postnummer i dina butiksinställningar och försök igen + Postnumret i butiksadressen är ogiltigt + Ange din butiksadress för att fortsätta + Adressen kan inte uppdateras med en tom e-postadress. Kontrollera att du kör den senaste versionen av WooCommerce. Inte nu Installera Jetpack - Tillåt flera användare att komma åt WooCommerce Mobile. Användarprofiler + Tillåt flera användare att komma åt WooCommerce Mobile. Nya analysvyer gör det möjligt att se besökare, rapporter med mera. Analys Få push-notiser för nya beställningar, recensioner med mera levererade till din enhet. Push-notiser Installera det kostnadsfria Jetpack-tillägget för den bästa mobilupplevelsen. Få ut så mycket som möjligt av din butik - Använd som leveransadress Använd som faktureringsadress Filter (%d) Filter @@ -2046,14 +2081,14 @@ Language: sv_SE Visa beställningar Filtrerade beställningar Alla beställningar + Använd som leveransadress Berätta mer om %s … - Beskriv din produkt för dina framtida kunder … Läsarens serienummer kopierad till urklipp - Lägg till faktureringsadress + Beskriv din produkt för dina framtida kunder … Lägg till leveransadress - Lägg till kundanteckning + Lägg till faktureringsadress Faktureringsadress - Leveransadress + Lägg till kundanteckning Adress Land Postnummer @@ -2065,7 +2100,9 @@ Language: sv_SE E-post Efternamn Förnamn + Leveransadress Redigera en kundbeställningsanteckning + OK Det gick inte att hämta SSR. Kontrollera WooCommerce -> Status i WP-admin. Det gick inte att dela systemstatusrapporten Det gick inte att kopiera SSR till urklipp @@ -2076,57 +2113,56 @@ Language: sv_SE Grattis, du kan nu ta emot kredit- och betalkortsbetalningar med WooCommerce Payments! Ta emot betalningar med en kortläsare Belopp måste vara minst %1$s - OK - Bild på ny funktionsikon - Växla butik - Uppdatering av produkt %1$s misslyckades - %1$d bilder har lagts till för produkten %2$s Produkt uppdaterad Uppdaterar produkt %1$s - Bilduppladdning kommer fortsätta i bakgrunden - Spara kvitto och fortsätt OK - Vi kan inte läsa in Beställningstillägg för närvarande Något gick fel - Vad som är nytt i WooCommerce + Uppdatering av produkt %1$s misslyckades + Spara kvitto och fortsätt + Bilduppladdning kommer fortsätta i bakgrunden + Växla butik + %1$d bilder har lagts till för produkten %2$s + Bild på ny funktionsikon + Vi kan inte läsa in Beställningstillägg för närvarande + Kategori Visa utökningar + Vad som är nytt i WooCommerce Vi kan tyvärr inte ändra den här funktionsinställningen för tillfället - Kategori Du har en ny recension! 🌟 Du har en ny beställning! 🎉 %d artikel + Sparar din produkt + %d produkter + %d produkt + Försök igen med ett annat kort + Försök igen med samma kort + Ta bort kortet + Se till att kortläsaren är ansluten. + %d arbetsdagar + %d arbetsdag %d merförsäljningsprodukter %d merförsäljningsprodukt %d korsförsäljningsprodukter %d korsförsäljningsprodukt - %d produkter - %d produkt Produktutökningar - Sparar din produkt Väntande recension - Se till att kortläsaren är ansluten. - Försök igen med ett annat kort Prova att trycka på, föra in eller svepa ditt kort Flera kort upptäckta. Prova igen med endast ett kort - Ta bort kortet - Försök igen med samma kort %d poster %d artikel - %d arbetsdagar - %d arbetsdag Vi kunde inte verifiera leveransadressen automatiskt: %s Vi kunde inte automatiskt verifiera ursprungsadressen. Visa adressen i Google Maps för att verifiera att den är korrekt. Vi arbetar på att göra det enklare för dig att se produkttillägg från din enhet! För tillfället kan du endast se tilläggen för dina beställningar. Du kan skapa och redigera dessa tillägg i din webbadminpanel. - Visa utökningar från din enhet! + Spara Om du byter namn på ett tillägg i din webbadminpanel, observera att vissa beställningar inte längre kommer att visa tillägget i appen. Visa utökningar - Spara - Ladda upp information (%d) + Visa utökningar från din enhet! %d filer kunde inte laddas upp - %d fil kunde inte laddas upp + Ladda upp information (%d) Media kunde inte hittas - Du kan redigera produkttillägg i webbadminpanelen. <a href=\'\'>Läs mer</a> om att ladda upp bilder + %d fil kunde inte laddas upp + Du kan redigera produkttillägg i webbadminpanelen. Vi kunde inte verifiera personliga betalningar för den här butiken. Det gick inte att verifiera personliga betalningar för den här butiken. Firmware: %s @@ -2138,77 +2174,61 @@ Language: sv_SE Skriv ut fraktetikett Fraktetikett köpt! Skriv ut fraktetiketter + Håll din läsare laddad + Behöver du lite hjälp? <a href=\'\'>Kontakta support</a> + Svep, tryck eller sätt in kort + Läsare ansluten Personliga betalningar Det tar ungefär tre timmar att ladda din läsare - Håll din läsare laddad Din läsare går in i viloläge efter 10 minuter av inaktivitet. Det är bara att trycka på strömknappen för att återansluta den. Automatisk återanslutning Det är bara att svepa, trycka eller infoga kort på läsaren för att ta emot betalningar. - Svep, tryck eller sätt in kort Grattis, du kan nu ta emot kredit- och betalkortsbetalningar! - Läsare ansluten - Behöver du lite hjälp? <a href=\'\'>Kontakta support</a> <a href=\'\'>Läs mer</a> om att ta emot betalningar med din mobila enhet och att beställa kortläsare Personliga betalningar är inte tillgängliga i testläget. Stäng av det för att fortsätta. Personliga betalningar är för närvarande inte tillgängliga Det finns krav som inväntar granskning i ditt konto. Slutför dessa krav senast den %1$s för att fortsätta ta emot personliga betalningar. - Ditt konto har krav som inväntar granskning Du har minst ett försenat krav i ditt konto. Ta hand om det för att återuppta personliga betalningar. Personliga betalningar är för närvarande inte tillgängliga Du kommer att kunna ta emot personliga betalningar så snart vi har slutfört granskningen av ditt konto. + Ditt konto har krav som inväntar granskning + Uppdatera efter uppdatering + Uppdatera WooCommerce Payments Personliga betalningar är för närvarande inte tillgängliga Tyvärr kan vi inte erbjuda personliga betalningar för den här butiken. - Uppdatera efter uppdatering En föråldrad version av utökningen WooCommerce Payments är installerad för din butik. Uppdatera den för att ta emot personliga betalningar. - Uppdatera WooCommerce Payments Du är nästan där! Slutför konfigurationen av WooCommerce Payments för att börja ta emot personliga betalningar. - Slutför konfigurationen av WooCommerce Payments i adminpanelen för din butik + Ansluter till ditt konto + Uppdatera efter installation + Behöver du lite hjälp? <a href=\'\'>Kontakta support</a> Uppdatera efter aktivering - Utökningen WooCommerce Payments är installerad för din butik, men den har inte aktiverats. Aktivera den för att ta emot personliga betalningar. + Aktiverar paket + Välj ett paket att aktivera. + Alla tillgängliga paket har aktiverats + Installera WooCommerce Payments Aktivera WooCommerce Payments - Uppdatera efter installation + Slutför konfigurationen av WooCommerce Payments i adminpanelen för din butik + Utökningen WooCommerce Payments är installerad för din butik, men den har inte aktiverats. Aktivera den för att ta emot personliga betalningar. Du måste installera den kostnadsfria utökningen WooCommerce Payments för din butik för att ta emot personliga betalningar. - Installera WooCommerce Payments <a href=\'\'>Läs mer</a> om att ta emot betalningar med din mobila enhet och att beställa kortläsare - Behöver du lite hjälp? <a href=\'\'>Kontakta support</a> Du kan fortfarande ta emot personliga kontanta betalningar genom att aktivera betalningsmetoden \"Postförskott\" i din butik - Vi stöder inte personliga kortbetalningar i %1$s - Ansluter till ditt konto Personliga betalningar Dubbelkolla måtten eller vikten på ditt paket eller prova att använda ett annat paket i Paketinformation Det finns inga fraktavgifter tillgängliga - Alla tillgängliga paket har aktiverats - Aktiverar paket - Välj ett paket att aktivera. - Obligatoriskt fält + Vi stöder inte personliga kortbetalningar i %1$s Stäng + Obligatoriskt fält + Attribut skapade + Ingen internetanslutning + Ingen anslutning till server + Denna betalning kunde inte bearbetas Variationen har skapats Generera ny variation Du kan nu skapa och hantera produktvariationer! Generera variation Nu när du har lagt till attribut kan du skapa din första variation! - Attribut skapade - %1$s%% slutförd Att avbryta en pågående programvaruuppdatering är inte att rekommendera - Denna betalning kunde inte bearbetas - Ingen anslutning till server - Ingen internetanslutning - Skicka i originalförpackning - Lägg till i nytt paket - Denna vara finns för närvarande i %s. Vart vill du flytta den? - Avbryt - Flytta - Flytta vara - ”%1$s” sparat - Misslyckades att skapa paket. Försök igen. - Misslyckades att skapa paket: okänt API-problem. - Misslyckades att skapa paket: %1$s - Vänta … - Skapar nytt paket - Ogiltigt värde. - Detta fält är obligatoriskt. - Vikt för tomt paket - Tom förpackningsvikt (%1$s) + %1$s%% slutförd Höjd (%1$s) Bredd (%1$s) Längd (%1$s) @@ -2217,133 +2237,147 @@ Language: sv_SE Låda Välj pakettyp Pakettyp - Konfigurera paketet som du kommer att använda för att skicka dina produkter. Vi kommer att spara den för framtida beställningar. + Avbryt + Flytta + Vänta … + Skapar nytt paket + Ogiltigt värde. + Detta fält är obligatoriskt. + Vikt för tomt paket Lägg till nytt paket Skapa nytt paket + Misslyckades att skapa paket. Försök igen. + Misslyckades att skapa paket: okänt API-problem. + Misslyckades att skapa paket: %1$s + ”%1$s” sparat + Skicka i originalförpackning + Lägg till i nytt paket + Denna vara finns för närvarande i %s. Vart vill du flytta den? + Flytta vara + Tom förpackningsvikt (%1$s) Paketets mått måste vara större än noll. Uppdatera måtten för din vara i sektionen Frakt på din produktsida för att fortsätta. - Originalförpackning - Varumått - Vara som skickas för sig - Beställningsstatus uppdaterad + Konfigurera paketet som du kommer att använda för att skicka dina produkter. Vi kommer att spara den för framtida beställningar. Skicka Skriv ut Se kvitto Avbryt ändå + Beställningsstatus uppdaterad + Originalförpackning + Varumått + Vara som skickas för sig + Slå på Bluetooth Det gick inte att uppdatera läsarens programvara Sökningen efter programvaruversionsuppdateringar misslyckades <a href=\'\'>Läs mer</a> om att ta emot mobilbetalningar och beställa kortläsare - Slå på Bluetooth - Ingen läsare ansluten Vi kunde inte ansluta din läsare Anslut Flera läsare hittade Beställningen är redan betald + Ingen läsare ansluten + Betalningsmetod har lagts till + Lägg till ett kreditkort + Ange ett giltigt telefonnummer Tack för ditt köp! Klicka på länken nedan för att visa ditt betalningskvitto.\n\n%s Det gick inte att ladda ner tullformuläret Skriv ut tullfaktura Skriv ut tullformulär Ett tullformulär måste skrivas ut och inkluderas i denna internationella försändelse Tullformulär - Betalningsmetod har lagts till - Lägg till ett kreditkort - Ange ett giltigt telefonnummer Skriv ut tullformulär + Ditt kvitto från %s + Lägg till produkt + Din kund valde %1$s Utforska hur du kan öka din butiksförsäljning. Börja sälja idag genom att lägga till din första produkt i butiken. - Lägg till produkt Variationsattribut Aktivera Bluetooth på den mobila enheten - Det gick inte att hämta beställningen. Beställningens status i appen kan vara föråldrad. - Ditt kvitto från %s Uppdaterar beställning Uppdaterar appstatusen - Din kund valde %1$s - Tullformulär kräver ett tiosiffrigt telefonnummer - Tullformulär ifyllt + Det gick inte att hämta beställningen. Beställningens status i appen kan vara föråldrad. + 1 variation + Lär dig mer om att skriva ut kvitton med din enhet + Aktivera Bluetooth- eller Wifi-anslutning på din skrivare. + Parkoppla och anslut skrivaren till din mobil när du uppmanas till det. + Justera pappersstorleken efter behov och välj ”Skriv ut” när du är redo att skriva ut kvittot. Om du har problem med att skriva ut från din enhet kontaktar du kundsupporten för din skrivare. Om utskrift inte är tillgänglig kan du alltid spara ditt kvitto som PDF och skicka det via e-post för att skriva ut det från en annan enhet. - Justera pappersstorleken efter behov och välj ”Skriv ut” när du är redo att skriva ut kvittot. - Parkoppla och anslut skrivaren till din mobil när du uppmanas till det. + Tullformulär ifyllt När du väljer \"Skriv ut kvitto\" efter att ha godkänt betalningen, ersätt \"Spara som PDF\" med \"Alla skrivare\" och sök efter ny skrivare. - Aktivera Bluetooth- eller Wifi-anslutning på din skrivare. Se till att Print Service-tillägget för din skrivare är installerat. - Lär dig mer om att skriva ut kvitton med din enhet För att skapa en variation måste du först ställa in dess attribut (dvs. \"Färg\", \"Storlek\") - 1 variation %1$s variationer + Tullformulär kräver ett tiosiffrigt telefonnummer USPS-spårning Uppdaterar din läsares programvara Programvaruuppdatering Läsarens programvara har uppdaterats - OKÄNT KORTLÄSARNAMN + Karantän + Ingen + Annat + Prov + Innehållsdetaljer + Dokument + Beskrivning + Detta fält är obligatoriskt + Anpassad rad %1$d + Vikt (%1$s per enhet) + Värde (%1$s per enhet) Koppla från läsare - Uppdatera din läsares programvara för att fortsätta ta emot betalningar - Uppdatera läsarens programvara - %s%% batteri ANSLUTEN LÄSARE Anslut kortläsare - Sätt på kortläsaren och placera den bredvid den mobila enheten Se till att kortläsare är laddad Anslut din kortläsare - Kort avvisades Ansluter till läsaren - Förbereder för att ta emot betalning - Det deklarerade värdet måste vara större än noll + Annat Vikt måste vara större än noll - Detta fält är obligatoriskt + Land där produkten tillverkades eller monterades + Ursprungsland + Ogiltigt format + Begränsningsdetaljer + Begränsningstyp + Innehållstyp + Returnera till avsändare om paketet inte kan levereras + upp till %s + Paketinnehåll + Sätt på kortläsaren och placera den bredvid den mobila enheten + Kort avvisades Beskriv vilken typ av begränsningar detta paket måste ha. Beskriv vilken typ av varor detta paket innehåller. - Vikt (%1$s per enhet) - Värde (%1$s per enhet) + OKÄNT KORTLÄSARNAMN + Uppdatera din läsares programvara för att fortsätta ta emot betalningar + Uppdatera läsarens programvara + %s%% batteri + Förbereder för att ta emot betalning + Det deklarerade värdet måste vara större än noll %1$s om HS-tariffnummer %1$s om internt transaktionsnummer - Anpassad rad %1$d - Annat Sanitär/fytosanitär inspektion - Karantän - Ingen - Annat - Prov Presenter - Dokument Handelsvaror - Land där produkten tillverkades eller monterades - Ursprungsland Tariffnumret måste vara 6 siffror långt HS-tariffnummer (valfritt) - Beskrivning - Paketinnehåll ITN krävs för försändelser till %1$s. ITN krävs för frakt av artiklar till ett värde som överstiger 2 500 USD per tariffnummer - Ogiltigt format - Begränsningsdetaljer - Innehållsdetaljer - Begränsningstyp - Innehållstyp - Returnera till avsändare om paketet inte kan levereras - upp till %s - Om du har aktiverat den här inställningen kommer kunden att få ett bekräftelsemeddelande via e-post när beställningen har slutförts. - Granska beställning - 🎉 Beställning slutförd! + Hoppa över Verifierar roll … Du har inte den korrekta användarrollen + Redigera och lägg till nya produkter var som helst + Granska beställning Lär dig mer om roller och behörigheter + Spåra försäljning och högpresterande produkter + Om du har aktiverat den här inställningen kommer kunden att få ett bekräftelsemeddelande via e-post när beställningen har slutförts. + 🎉 Beställning slutförd! Den här appen har endast stöd för användarrollerna Administratör och Butikschef. Kontakta butiksägaren för att uppgradera din roll. - Redigera och lägg till nya produkter var som helst Hantera och redigera beställningar i farten - Spåra försäljning och högpresterande produkter - Hoppa över Extern produkt Grupperad produkt Variabel produkt En unik digital produkt som tjänster, nedladdningsbara böcker, musik eller videor - En unik fysisk produkt som du kan behöva frakta till kunden Enkel fysisk produkt Öppna inställningar Öppna inställningar + En unik fysisk produkt som du kan behöva frakta till kunden Bluetooth är inaktiverat - Plats är inaktiverad - Saknar nödvändig exakt platsbehörighet Det gick inte att ansluta till läsaren. Ansluter till läsaren Anslut läsaren @@ -2351,62 +2385,68 @@ Language: sv_SE Söker efter läsare Antal artiklar Skapa ny leveransetikett + Plats är inaktiverad + Saknar nödvändig exakt platsbehörighet Enkel virtuell produkt - Vill du ta bort denna variant? - Genererar variation Tar bort produkt Skicka kvitto Skriv ut kvitto + Betalning lyckades + Betalning misslyckades + Tryck eller infoga för att betala + Vill du ta bort denna variant? Fångar upp betalning Behandlar betalning Läsaren är redo - Betalning misslyckades - Betalning lyckades Ta emot betalning - Tryck eller infoga för att betala Det gick inte att förhandsgranska fraktsedeln. Installera en app för PDF-visning och försök igen. Vi kunde inte detektera någon WordPress-webbplats på den angivna adressen. Se till att WordPress är installerat och att du kör den senaste tillgängliga versionen. flera fraktrader + Genererar variation + Vänta … + Spara till senare Kunde inte markera beställningen som slutförd + Etiketter som är äldre än 30 dagar kan inte återbetalas + Skriv ut fraktetikett + Fraktetikett köpt! Ett fel uppstod vid köp av etiketterna - Vänta … Köpa etikett Etikettbilder som är äldre än 180 dagar tas bort av våra teknikpartners i generella säkerhets- och dataskyddssyften. - Skriv ut fraktetikett - Spara till senare - Fraktetikett köpt! - Etiketter som är äldre än 30 dagar kan inte återbetalas - Typ + Typ av variation, t.ex. storlek eller färg Ändra namn + Typ Det gick inte att byta namn på ditt attribut - Typ av variation, t.ex. storlek eller färg Byt namn på attribut + Attribut + och + Ta bort detta attribut? Var det inte meningen att skapa ett nytt konto? Gå tillbaka och skriv din e-postadress igen. - Anslut kortläsare Hantera kortläsare Butiksinställningar - Attribut + Anslut kortläsare Du kan återbetala %1$s Ta emot betalning - och - Ta bort detta attribut? Valfri Fel när dina attribut sparades - Det är bara webbplatsens ägare som kan hantera betalningsmetoderna för fraktetiketter. Kontakta butiksägaren %1$s (%2$s) för att hantera betalningsmetoder. + Signatur obligatoriskt (%s) Lägg till variationer Lägg till variation - Lägg till din första variant %s totalt + Det är bara webbplatsens ägare som kan hantera betalningsmetoderna för fraktetiketter. Kontakta butiksägaren %1$s (%2$s) för att hantera betalningsmetoder. %s avgifter valda Berättigar till gratis signaturkrav Berättigar till gratis upphämtning - Försäkring (%s) - spårning Inkluderar %s Måste signeras av en vuxen (%s) - Signatur obligatoriskt (%s) + spårning + Försäkring (%s) Kunden betalade %1$s av %2$s för frakt - När du köper fraktetiketter med WooCommerce, får du 5 % till 40 % i rabatt jämfört med postkontoret. + Lägg till din första variant + gratis + Annat + Delsumma + Ett alternativ med detta namn finns redan + Ett attribut med detta namn finns redan Vad innebär rabatt på WooCommerce-tjänster? Det gick inte att hämta leveransalternativen Transportföretag och avgifter @@ -2415,40 +2455,33 @@ Language: sv_SE Ordersumma Läs mer om rabatt på WooCommerce-tjänster Rabatt på WoCommerce-tjänster - Delsumma Beställningssammanfattning för fraktetiketter - gratis - Annat - Ett alternativ med detta namn finns redan - Ett attribut med detta namn finns redan Lägg till varje alternativnamn och tryck på retur Eller tryck för att välja ett befintligt alternativ Namn på alternativ - Ett fel uppstod när dina inställningar skulle sparas + När du köper fraktetiketter med WooCommerce, får du 5 % till 40 % i rabatt jämfört med postkontoret. Vänta … Sparar dina inställningar Löper ut %1$s - E-posta inköpskvitton till %1$s (%2$s) på %3$s - Kreditkort hämtas från följande WordPress.com-konto: %1$s <%2$s> - %1$s****%2$s Lägg till ett annat kreditkort Betalningsmetod vald Vänta … + %1$s****%2$s + Ett fel uppstod när dina inställningar skulle sparas + E-posta inköpskvitton till %1$s (%2$s) på %3$s + Kreditkort hämtas från följande WordPress.com-konto: %1$s <%2$s> Hämtar dina inställningar - Kreditkort slutar på %1$s Paypal VISA MasterCard Discover American Express - Eller tryck för att välja ett befintligt attribut - Nytt attributnamn Lägg till attribut Attribut Redigera attribut - Total förpackningsvikt: %1$s %2$s - %1$d varor i %2$d förpackningar - Total förpackningsvikt: %1$s %2$s + Eller tryck för att välja ett befintligt attribut + Nytt attributnamn + Kreditkort slutar på %1$s Anpassade paket Kan inte hämta produkter Vissa obligatoriska fält är tomma. @@ -2457,41 +2490,44 @@ Language: sv_SE Vänta … Laddar in paket! Packet %1$d - %d varor Kan inte ladda paketdefinitioner - Inkluderar förpackningsvikt - Total förpackningsvikt (%1$s) - Vald förpackning Paketdetaljer Flytta - Poster att slutföra Föreslagen adress Angiven adress - Vi har ändrat den adress du angav något. Använd den föreslagna adressen om den stämmer för att försäkra korrekt leverans. Redigera vald adress Använd vald adress + %1$d varor i %2$d förpackningar + Total förpackningsvikt: %1$s %2$s + Inkluderar förpackningsvikt + Total förpackningsvikt (%1$s) + Vald förpackning + Poster att slutföra + Vi har ändrat den adress du angav något. Använd den föreslagna adressen om den stämmer för att försäkra korrekt leverans. + Total förpackningsvikt: %1$s %2$s + %d varor Laddar in adressdata Nya funktioner tillgängliga! - Hitta på karta - Kontakta kunden + Adress hittades inte Ogiltig gata Husnummer saknas - Adress hittades inte - Vi kunde inte verifiera leveransadressen automatiskt. Visa i Google Maps eller testa att kontakta kunden för att verifiera att adressen stämmer. - Adressvalideringen misslyckades - Vänta … - Adressvalideringen pågår - Det gick inte att läsa in adressdata - Använd adressen som angavs - Land Postnummer - Delstat + Vänta … Ort Telefon Företag Namn - Google Maps-appen hittades + Land + Delstat + Använd adressen som angavs + Kontakta kunden + Vi kunde inte verifiera leveransadressen automatiskt. Visa i Google Maps eller testa att kontakta kunden för att verifiera att adressen stämmer. + Adressvalideringen misslyckades + Adressvalideringen pågår + Det gick inte att läsa in adressdata + Hitta på karta Vänta … + Google Maps-appen hittades Bildborttagning på produktvarianter stöds i WooCommerce 4.7 eller senare. Vänta Lägger till spårning @@ -2505,102 +2541,102 @@ Language: sv_SE Förpackningsinformation Skapa fraktetikett Läs mer - Skippa kön på postkontoret genom att skriva ut fraktetiketter till rabatterade priser hemma med din mobila enhet! Spara tid och pengar genom att fullfölja med WooCommerce Shipping WooCommerce Shipping Markera ordern som slutförd - Lär dig mer om att skapa etiketter med din mobila enhet Skapa fraktetikett - Du kan nu skapa fraktetiketter för alla fysiska beställningar direkt från din enhet med hjälp av gratistillägget WooCommerce Shipping. Tryck på \"Skapa fraktetikett\" för att prova vår betafunktion! Skapa fraktetiketter från din enhet! + Du kan nu skapa fraktetiketter för alla fysiska beställningar direkt från din enhet med hjälp av gratistillägget WooCommerce Shipping. Tryck på \"Skapa fraktetikett\" för att prova vår betafunktion! + Lär dig mer om att skapa etiketter med din mobila enhet + Skippa kön på postkontoret genom att skriva ut fraktetiketter till rabatterade priser hemma med din mobila enhet! + Redigera Avgifter Nettobetalning Betald Läs mer om att ansluta Jetpack - Redigera Validera Dra och släpp för att ändra ordning på foton - Inställningar för nedladdning + Radera + Fil-URL + Lägg till fil + 1 fil + %1$d filer + Fil + Avbryt + Ja, ändra Ange ett giltigt namn Ange fil-URL - WordPress mediabibliotek - Kontrollera att den angivna URL:en är giltig Vänta … Laddar upp filer + Filnamn + Inställningar för nedladdning + Kontrollera att den angivna URL:en är giltig Fel vid uppladdning av filen Lägg till nedladdningsbar fil - Lägg till nedladdningsbar fil från Inkludera nedladdningsbara filer med köp - Avbryt - Ja, ändra Alla filer som för närvarande är associerade med den här produkten kommer att tas bort. Är du säker på att du vill ta bort möjligheten att ladda ned filer när produkten köps? - Fil Är du säker på att du vill ta bort den här filen? Nedladdningsbar produkt - Radera Tidsgräns för nedladdning Nedladdningsgräns Ange antalet dagar innan en nedladdningslänk löper ut, eller lämna fältet tomt om länken aldrig löper ut. Ange antalet gånger som filen kan laddas ned eller lämna fältet tomt för obegränsade nerladdningar Detta är namnet på filen som visas för kunden - Filnamn Detta är URL:en för filen som kunderna får tillgång till. URL:er som anges bör redan vara kodade. - Fil-URL - Lägg till fil - 1 fil - %1$d filer Du kan behöva <b>konfigurera Wi-Fi-utskrift direkt på själva skrivaren.</b> Kontrollera att skrivarens fasta programvara är uppdaterad. Anvisningar finns i skrivarens dokumentation. Du kan välja din enhets <b>standardutskriftstjänst</b> eller installera din <b>skrivares varumärkesapp</b> (detta bör visas som ett rekommenderat alternativ) Se till att din skrivare och din enhet är anslutna till <b>samma Wi-Fi-nätverk</b> - Testa det nya enkla, länkade och grupperade produktskapandet medan vi gör oss redo för lansering - Öka försäljningen med merförsäljning och korsförsäljning + WordPress mediabibliotek + Lägg till nedladdningsbar fil från Redigera produkter Lägg till produkter + Öka försäljningen med merförsäljning och korsförsäljning Produkter som marknadsförs i kundvagnen när den nuvarande produkten är vald + Testa det nya enkla, länkade och grupperade produktskapandet medan vi gör oss redo för lansering Korsförsäljning Produkter som marknadsförs istället för den för närvarande visade produkten (dvs. mer lönsamma produkter) Merförsäljning Länkade produkter %1$s%2$s x %3$s Skaffa en länk för inloggning via e-post - Hmm. Vi hittar inget konto hos WordPress.com som är kopplat till denna e-postadress. - Testa att visa Beställningstillägg medan vi gör oss redo för lanseringen + Välj pappersstorlek + Pappersstorlek Skapar produkter - Inställningar - Ett fel inträffade när produkten skulle slängas Produkt flyttad till papperskorg Flytta till papperskorg Vill du flytta denna produkt till papperskorgen? - Släng produkt Denna produkt har inga variationer än - Det går endast att lägga till alternativ som storlek och färg på webben. Dessa kommer att visas som alternativ på produktsidan på din webbplats. Skapa produkter från appen! Produkt hittades inte - Om du fortfarande har problem med att skriva ut från din enhet kan du <b>spara din etikett som en PDF-fil</b> och skicka den med e-post för att skriva ut den från en annan enhet. - När du har valt <b>\"Skriv ut fraktetikett\"</b> kan du behöva välja och lägga till en skrivare om du inte har skrivit ut från den här enheten tidigare. + Hmm. Vi hittar inget konto hos WordPress.com som är kopplat till denna e-postadress. + Inställningar + Ett fel inträffade när produkten skulle slängas + Släng produkt + Det går endast att lägga till alternativ som storlek och färg på webben. Dessa kommer att visas som alternativ på produktsidan på din webbplats. Alternativ för etikettformat - Skriv ut med din enhet Etikett (4 x 6 tum) Letter (8,5 x 11 tum) Legal (8,5 x 14 tum) Fel vid förhandsgranskning av fraktetikett - Vet du hur du skriver ut med din mobila enhet? Se alternativen för etikettlayout och pappersstorlek Skriv ut fraktetikett - Välj pappersstorlek - Pappersstorlek - Om du redan har använt etiketten på ett paket är det ett brott mot våra användarvillkor att skriva ut och använda den igen. Om det inträffade ett utskriftsfel när du köpte etiketten kan du skriva ut den igen. Vi arbetar för att göra det enklare för dig att skriva ut fraktetiketter direkt från din enhet! Om du har skapat fraktetiketter för den här ordern i butiksadmin i WooCommerce Shopping kan du nu skriva ut dem under Beställningsinformation här. Skriv ut fraktetiketter från din enhet! + Skriv ut med din enhet + Om du redan har använt etiketten på ett paket är det ett brott mot våra användarvillkor att skriva ut och använda den igen. + Om du fortfarande har problem med att skriva ut från din enhet kan du <b>spara din etikett som en PDF-fil</b> och skicka den med e-post för att skriva ut den från en annan enhet. + När du har valt <b>\"Skriv ut fraktetikett\"</b> kan du behöva välja och lägga till en skrivare om du inte har skrivit ut från den här enheten tidigare. Skriv ut fraktetikett + Vet du hur du skriver ut med din mobila enhet? + Testa att visa Beställningstillägg medan vi gör oss redo för lanseringen \u0022%1$s\u0022 Produktutkast sparat - Det gick inte att spara produktutkastet Sparar utkast - I papperskorgen Spara som utkast + Det gick inte att spara produktutkastet + I papperskorgen Bekräftelse av registrering Återställ ditt lösenord Ange din webbplatsadress @@ -2629,100 +2665,99 @@ Language: sv_SE Skicka länk via e-post Ge feedback Produkt publicerad - Fel vid publicering av produkt - Publicerar produkt PUBLICERA Ny produkt - Endast ett foto kan visas per produktvariant - Byt ut foto + Publicerar produkt + Fel vid publicering av produkt Lägg till foto + Byt ut foto + Endast ett foto kan visas per produktvariant Lägg till bild för variant Lär dig hur man installerar och ansluter Jetpack - För att använda den här appen för %1$s behöver du ha anslutit Jetpack-tillägget till din butik. Logga in med ett annat konto Välj butik att ansluta Fortsätt med WordPress.com - En produkt med variationer som färg eller storlek + För att använda den här appen för %1$s behöver du ha anslutit Jetpack-tillägget till din butik. + Ange lösenord %d produkt vald %d produkter valda Lägg till produkter till gruppen Lägg till produkt - Ange lösenord - Tillbaka till butik + En produkt med variationer som färg eller storlek Kontakta oss här - Tänk på att detta inte är ett supportärende och att vi inte kan adressera individuell feedback.\n\nBehöver du hjälp? %1$s - Tack för att du delar dina\n tankar med oss Feedback skickad Vänta … Laddar in Hur kan vi förbättra? Ja, ändra - Om du ändrar produkttypen ändras en del av produktinformationen - Är du säker på att du vill ändra produkttypen? - Länk till en produkt på en extern webbplats - En samling relaterade produkter Välj en produkttyp Skicka feedback Vissa variationer har inga priser - Variationer utan pris kommer inte att visas i din butik - Variation uppdaterad - Ta bort den grupperade produkten Grupperade produkter Ändra produkttyp - Inget pris angivet Aktiverad + %1$s lämnade en recension + Ta bort den grupperade produkten + Variation uppdaterad + Tillbaka till butik + Tänk på att detta inte är ett supportärende och att vi inte kan adressera individuell feedback.\n\nBehöver du hjälp? %1$s + Tack för att du delar dina\n tankar med oss + Om du ändrar produkttypen ändras en del av produktinformationen + Är du säker på att du vill ändra produkttypen? + Länk till en produkt på en extern webbplats + En samling relaterade produkter + Variationer utan pris kommer inte att visas i din butik + Inget pris angivet Du måste ange försäljningspriset om en försäljning är schemalagd Du kan nu redigera grupperade, externa och variabla produkter, ändra produkttyp och uppdatera kategorier och etiketter. - %1$s lämnade en recension - Jag gillar den Kunde vara bättre Tycker du om WooCommerce-appen? + Jag gillar den Fel vid uppdatering av variation Fel vid hämtning av variation Fel uppstod när etiketter lades till Lägger till etiketter Din återbetalning bearbetas. Vänta … - Begäran om återbetalning har skickats Återbetalningsetikett (-%1$s) - Belopp berättigat för återbetalning Inköpsdatum - Du kan begära en återbetalning för en fraktetikett som inte har använts för att skicka ett paket. Den kommer att ta minst 14 dagar att behandla. Begär en återbetalning + Belopp berättigat för återbetalning Fraktetikett för återbetalning - Fysisk - Ett kort utdrag om din produkt - Gör dina produkter lättare att hitta med etiketter + Du kan begära en återbetalning för en fraktetikett som inte har använts för att skicka ett paket. Den kommer att ta minst 14 dagar att behandla. + Begäran om återbetalning har skickats Organisera dina produkter i relaterade grupper - Lägg till vikt och dimensioner - Lägg till fler detaljer - Organisera dina produkter i etiketter - Lägg till din första etikett + Gör dina produkter lättare att hitta med etiketter + Ett kort utdrag om din produkt + Fysisk Etiketter Lägg till etikett - Inaktiverat Virtuell produkt Lägg till fler detaljer %1$s produkt nedladdningsbar %s produkt + Lägg till fler detaljer + Organisera dina produkter i etiketter + Lägg till vikt och dimensioner + Lägg till din första etikett + Inaktiverat Återstående produkter + %1$s\n%2$s + Kreditkort + Betalningsmetod %1$s \u2022 %2$s - %1$s etikettåterbetalning begärd Spåra försändelse - %1$s\n%2$s Dölj information om försändelse Visa försändelseinformation - Kreditkort - Betalningsmetod Transportföretag och avgifter Information om förpackning Leverans Avsändare Förpackning %d + %1$s etikettåterbetalning begärd SKU: %1$s %1$s (%2$s alternativ) Fraktetiketter - Vänta … Lägger till kategori Överordnad kategori Kategorinamn @@ -2736,33 +2771,26 @@ Language: sv_SE Lägg till kategori Kategorier Gäst + Vänta … Integritetsnotis för användare i Kalifornien Behåll ändringar Fram till %1$s - Vi har lagt till fler redigeringsfunktionaliteter till produkter! Du kan nu uppdatera bilder, se förhandsgranskningar och dela dina produkter. Nya redigeringsalternativ tillgängliga - Begränsad redigering tillgänglig + Vi har lagt till fler redigeringsfunktionaliteter till produkter! Du kan nu uppdatera bilder, se förhandsgranskningar och dela dina produkter. Produkter %1$s x %2$s %1$s %2$s + Begränsad redigering tillgänglig Extern Enkel Publicerat privat Inga bilder ännu WordPress mediebibliotek WordPress mediebibliotek - Bestämmer produktens placering i katalogen. Ju lägre siffervärdet är desto högre kommer artikeln att vara i produktlistan. Du kan också använda negativa siffror. - Menysortering - Ett valfritt meddelande som kan skickas till kunden efter köpet - Denna text kommer att visas på knappen som länkar till den externa produkten + Slug + Produktlänk Knapptext Ange den externa URL:en till produkten - Produktlänk - Lägg till produktlänk - Aktivera recensioner - Detta är den URL-vänliga versionen av produktrubriken - Slug - Denna inställning avgör vilka butikssidor produkterna kommer att listas på. Utvald produkt Dold Endast sökresultat @@ -2776,16 +2804,7 @@ Language: sv_SE Synlighet Status Produktinställningar - Fel när lösenordet uppdaterades - Valt sorteringsalternativ - Valt filteralternativ Visa produkter - Filter \u2022 %d - Filter (%d) - Ö till A - Titel: Ö till A - A till Ö - Titel: A till Ö Äldsta Datum: äldsta till nyaste Nyaste @@ -2793,52 +2812,74 @@ Language: sv_SE Sortera efter Filter Inga produkter hittades - Alla Produkttyp %d valda Inte inställd Fler alternativ Rensa - Väntande recension - Om WooCommerce - Ställs in av strömsparläget - Systemstandard + Lägg till produktlänk + Aktivera recensioner + Detta är den URL-vänliga versionen av produktrubriken + Denna inställning avgör vilka butikssidor produkterna kommer att listas på. + Fel när lösenordet uppdaterades + Valt sorteringsalternativ + Valt filteralternativ + Denna text kommer att visas på knappen som länkar till den externa produkten + Menysortering + Bestämmer produktens placering i katalogen. Ju lägre siffervärdet är desto högre kommer artikeln att vara i produktlistan. Du kan också använda negativa siffror. + Ett valfritt meddelande som kan skickas till kunden efter köpet + Filter \u2022 %d + Filter (%d) + Ö till A + Titel: Ö till A + A till Ö + Titel: A till Ö + Alla Mörk - Ljus Utseende Kort sammanfattning om produkten Kort beskrivning - Reapriset måste vara lägre än det ordinarie priset + Om WooCommerce + Systemstandard + Väntande recension + Ställs in av strömsparläget + Ljus Ta bort slutdatum + Reapriset måste vara lägre än det ordinarie priset Lägg till frakt Produktbilderna laddas fortfarande upp. Vill du ignorera dina ändringar? Ange ett nummer Vi har lagt till redigeringsfunktionalitet till enkla produkter. Håll utkik för fler alternativ snart! + Till + Från + Momsinställningar + Momsstatus Frakt Momsbelagd Ingen Standardmoms Momsgrupp - Momsstatus - Momsinställningar - Till - Från Starta och avsluta en rea automatiskt Schemalägg rea i ditt administratörsarkiv - SKU används redan av en annan produkt - Fraktinställningar - Ingen fraktklass - Dimensioner Höjd Bredd Längd - Återbetalda produkter - %1$s (%2$s x %3$d) + Dimensioner + SKU används redan av en annan produkt + Fraktinställningar + Ingen fraktklass %1$s via %2$s - Är du säker på att du vill utfärda en återbetalning? Det här kan inte ångras. - Återbetalda produkter Återbetalningar + Återbetalda produkter + Återbetalda produkter + Är du säker på att du vill utfärda en återbetalning? Det här kan inte ångras. + %1$s (%2$s x %3$d) + från %1$s + Readatum + Lägg till pris + Handera lager + %1$s – %2$s Registrera dig på WordPress.com Vi hittade inga resultat för %s Få högkvalitativa produktrecensioner för din butik @@ -2850,56 +2891,51 @@ Language: sv_SE Hur många artiklar som finns i lager Antal Begränsa till en per order - Handera lager Hjälper att enkelt identifiera den här produkten - från %1$s - %1$s – %2$s - Readatum - Lägg till pris Lägg till lager Kollar upp dina beställningar … Ange text - Ange produktrubrik - Produkt sparad - Det gick inte att uppdatera produkten - Vänta … Beskriv din produkt Beskrivning Redigera beskrivning - Vill du ignorera dina ändringar? - Uppdatera + Det gick inte att uppdatera produkten + Vänta … + Ange produktrubrik + Produkt sparad Klart + Uppdatera + Vill du ignorera dina ändringar? Återbetalning pågår, vänta … Återbetala frakt Välj kvantitet Fraktåterbetalning Produktåterbetalning - %1$s x %2$s vardera %d artiklar valda Välj ingen Välj alla Väntar på återbetalningsbekräftelse … - Ändra storlek på och komprimera bilder för snabbare uppladdning - Bildoptimering + %1$s x %2$s vardera Ta ett foto - Välj från enheten Välj en uppladdningsmetod + Lägg till en produktbild + Ta bort foto + Lägg till foton + Foton + Lägg till bild + Ta bort + Kommande + Bildoptimering + Ändra storlek på och komprimera bilder för snabbare uppladdning + Välj från enheten Uppladdningar - Laddar upp bilder … %1$d av %2$d - Laddar upp bild … Det går inte att komma åt kameran Är du säker på att du vill ta bort den här bilden? Det gick inte att ta bilden Vänta tills den aktuella åtgärden har slutförts Det gick inte att ladda upp produktbilden Det gick inte att ta bort produktbilden - Lägg till en produktbild - Ta bort foto - Lägg till foton - Foton - Lägg till bild - Kommande - Ta bort + Laddar upp bilder … %1$d av %2$d + Laddar upp bild … Vi kunde inte komma åt din webbplats. För att lösa detta behöver du kontakta ditt webbhotell. Vi kunde inte komma åt din webbplats på grund av ett problem med <b>SSL-certifikatet</b>. För att lösa detta behöver du kontakta ditt webbhotell. Vi kunde inte komma åt din webbplats eftersom det kräver <b>HTTP-autentisering</b>. För att lösa detta behöver du kontakta ditt webbhotell. @@ -2908,8 +2944,8 @@ Language: sv_SE Logga in med dina inloggningsuppgifter. Logga in med dina inloggningsuppgifter för %1$s Skicka verifieringsmeddelande via e-post - Testa den nya produktredigeringsfunktionen då vi snart är klara för lansering Produktredigering + Testa den nya produktredigeringsfunktionen då vi snart är klara för lansering Det uppstod ett fel när ditt konto skulle hämtas. Du kan försöka igen nu eller stänga och försöka igen senare. Ett fel har uppstått. Logga in för att fortsätta Ansluter till din webbplats … @@ -2944,15 +2980,12 @@ Language: sv_SE Inga matchande produkter Inga produkter ännu %s i lager - I lager \u2022 %d variationer Produktbild %1$s lämnade en recension om %2$s Förkastad Den nya produktrecensionen kunde inte hämtas Produktrecensionerna kunde inte hämtas - Något gick fel med återbetalningen. Var vänlig försök igen. - Återbetalningen har skickats. - Din återbetalning för %s behandlas. Vänta … + I lager \u2022 %d variationer Offertikon Manuell återbetalning Återbetalningsinformation @@ -2970,7 +3003,10 @@ Language: sv_SE Återbetala %s %s tillgängligt för återbetalning Utfärda återbetalning + Något gick fel med återbetalningen. Var vänlig försök igen. + Återbetalningen har skickats. %1$s via %2$s + Din återbetalning för %s behandlas. Vänta … Förbättrad statistik Betafunktioner Väntar på betalning via %s @@ -2983,12 +3019,12 @@ Language: sv_SE Dagens statistik Logga in Har du redan Jetpack? %1$s - Försöker logga in med Jetpack … uppdatera appen för att fortsätta - För att använda den här appen för %1$s behöver du installera Jetpack-tillägget och ansluta det till det här kontot. \n\nNär detta är klart, starta om appen. Försök med en annan butik Databasen har nedgraderats, återskapar tabeller och läser in butiker Läser in butiker + Försöker logga in med Jetpack … + För att använda den här appen för %1$s behöver du installera Jetpack-tillägget och ansluta det till det här kontot. \n\nNär detta är klart, starta om appen. Inga transportföretag hittades Ange en fullständig webbplatsadress som example.com. Inga omdömen än! @@ -2999,12 +3035,11 @@ Language: sv_SE Det gick inte att hämta inställningarna: En del API:er är inte tillgängliga för den här OAuth app-ID + konto-kombinationen. Vi letar efter medarbetare! Kopiera spårningsnummer - Kollar efter WooCommerce … uppdatera appen + Kollar efter WooCommerce … Ingen adress specificerad Behöver du hjälp med att hitta e-postadressen som du använde för att ansluta? Webbplatsen på den här adressen är inte en WordPress-webbplats. Webbplatsen måste använda WordPress för att vi ska kunna ansluta till den. - Logga in med WordPress.com för att ansluta till <b>%1$s</b> Zimbabwe Zambia Yemen @@ -3141,6 +3176,7 @@ Language: sv_SE Jamaica Elfenbenskusten Italien + Logga in med WordPress.com för att ansluta till <b>%1$s</b> Israel Isle of Man Irland @@ -3247,24 +3283,15 @@ Language: sv_SE Afghanistan Åland Recension - Anpassat transportföretag Anpassad - Ange ett transportföretagsnamn Ange ett spårningsnummer - Välj ett transportföretag Vill du ta bort den här spårningen? Det gick inte att lägga till spårning Spårning av försändelse har lagts till - Det gick inte att hämta transportföretag - Valt transportföretag - Transportföretag Datum skickat Ange spårningslänk - Ange transportföretagsnamn Ange spårningsnummer - Välj transportföretag Spårningslänk (tillval) - Transportföretagsnamn Spårningsnummer Fraktbolag Lägg till spårning @@ -3277,26 +3304,35 @@ Language: sv_SE Spåra försändelse Du kan hitta e-postadressen som du använder för att ansluta till WordPress.com från din webbplatsadminsitration på %1$sJetpack Dashboard%2$s under %3$sAnslutningar > Kontoanslutning%4$s Vilken e-postadress ska jag använda för att logga in? - Behöver du hjälp med att hitta e-postmeddelandet? Jetpack är ett kostnadsfritt tillägg i WordPress som ansluter din butik till de verktyg som behövs för att ge den bästa möjliga mobilupplevelsen, inklusive pushmeddelanden och statistik Vad är Jetpack? Visa anslutna butiker Det ser ut som att %1$s är ansluten till ett annat WordPress.com-konto. Fortsätt redigera + Anpassat transportföretag + Ange ett transportföretagsnamn + Välj ett transportföretag + Det gick inte att hämta transportföretag + Valt transportföretag + Transportföretag + Ange transportföretagsnamn + Välj transportföretag + Transportföretagsnamn + Behöver du hjälp med att hitta e-postmeddelandet? + Tillåt + Tillåt inte + Läs mer + I lager + Slut i lager + Tillåt, men meddela kunden Logga in med ditt användarnamn och lösenord. Logga in med ditt WordPress.com användarnamn istället för din e-postadress. - Webbplatsen på denna adress är inte en WordPress-webbplats. För att vi ska kunna ansluta till den måste webbplatsen använda WordPress. Hjälpcenter - Virtuell - Grupperade - Variabel - Tillåt, men meddela kunden - Tillåt - Tillåt inte + Webbplatsen på denna adress är inte en WordPress-webbplats. För att vi ska kunna ansluta till den måste webbplatsen använda WordPress. Restnoterad - Slut i lager - I lager - Läs mer + Variabel + Grupperade + Virtuell Bilden kunde inte laddas Utkast Privat @@ -3342,11 +3378,11 @@ Language: sv_SE Prova nu Klart Peka för att byta butiker - Välj butik Logga ut Ändra orderstatus Klicka för att ändra orderstatus Tillämpa + Välj butik Nej tack Senare Betygsätt nu @@ -3357,14 +3393,14 @@ Language: sv_SE Dela din butiks URL Dela din butik Alla granskningar har markerats som lästa - Uppdatera butik till WooCommerce 3.5 Kan inte ansluta till %s + Uppdatera butik till WooCommerce 3.5 Avfärda - Ett fel uppstod när alla granskningar skulle markeras som lästa Markera alla som lästa Meddelande Ring Ring eller SMS:a kunden + Ett fel uppstod när alla granskningar skulle markeras som lästa Det gick inte att uppdatera produktrecensionsstatusen Det gick inte att uppdatera produktrecensionsinformationen Ta bort @@ -3374,19 +3410,19 @@ Language: sv_SE Visa produkten Hjälp och support Ljud, brådskande och aviseringspunkt - Hantera aviseringar Aviseringar Är du säker på att du vill logga ut från kontot %s? - Recension markerad som %1$s + Hantera aviseringar Om detta inaktiveras kommer noteringen att vara privat + Recension markerad som %1$s Det gick inte att hämta ordern Tillbaka Produktrecensionsaviseringar Ny order-aviseringar Till kund - Verifierar webbplats … Uppdatera instruktioner Sök + Verifierar webbplats … Uppdatera och %d mer. %d nya aviseringar @@ -3418,9 +3454,9 @@ Language: sv_SE Kraschrapporter Dela Version %s - HTTP-lösenord - HTTP-användarnamn - Autentisering krävs + Vi har gjort för många försök att leverera en verifieringskod via SMS – Vänta lite och be om en ny om en minut. + Det finns inget WordPress.com-konto som stämmer mot detta Google-konto. + Logga in på WordPress.com-kontot du använde för att ansluta Jetpack. Magisk länk har skickats Registrering via e-post Bekräftelse av kod @@ -3429,32 +3465,8 @@ Language: sv_SE Inloggning via magisk länk Webbplatsens inloggningsadress E-postadress för inloggning - Ett fel har inträffat. - Fyll i en autentiseringskod för att fortsätta. - Dubbelkontrollera ditt lösenord för att fortsätta. - Inloggningen avbruten - Vänta medan inloggningen pågår. - Inloggning pågår… - Tryck för att fortsätta. - Inloggad! - Ett nätverksfel har inträffat. Kontrollera anslutningen och försök igen. - Ange en webbplats som ligger på WordPress.com eller en WordPress-webbplats på egen server som är ansluten till Jetpack - Det gick inte att ansluta. Vi får fel 403 (förbjudet) när vi anropar XMLRPC-ändpunkten för din webbplats. Appen behöver detta för att kunna kommunicera med din webbplats. Kontakta webbhotellet för att lösa detta problem. - Det gick inte att ansluta. Din webbserver blockerar POST-anrop, som appen behöver för att kommunicera med din webbplats. Kontakta ditt webbhotell för att lösa detta problem. - Kunde inte ansluta. Obligatoriska XML-RPC-metoder saknas på servern. - Kontrollera att webbplatsens URL är giltig - Ett fel uppstod - Glömt ditt lösenord? - Ange en giltig epostadress - Kontrollerar e-post - Logga in igen för att fortsätta. - Logga in på WordPress.com-kontot du använde för att ansluta Jetpack. - Kunde inte hämta din profil - En dublett-webbplats har hittats. - Det går inte att lägga till denna webbplats. Den finns redan i appen. - Användarnamnet eller lösenordet som angavs är felaktigt + Har du inget konto? %1$sRegistrera dig%2$s Det tog för lång tid för Google att svara. Du kan behöva vänta tills du har en stabilare internetuppkoppling. - Registrerar med Google … Registrering med Google Registrering med e-postadress Genom att registrera dig accepterar du våra %1$sAnvändarvillkor%2$s. @@ -3464,20 +3476,55 @@ Language: sv_SE Det gick inte att sända e-postmeddelandet. Du kan försöka igen nu eller stänga och göra ett nytt försök senare. Skriv in din e-postadress för att skapa ditt nya WordPress.com-konto. Det gick inte att kontrollera e-postadressen. - \nDu kanske vill prova ett annat konto? + Ett fel har inträffat. + Fyll i en autentiseringskod för att fortsätta. + Dubbelkontrollera ditt lösenord för att fortsätta. + Inloggningen avbruten + Vänta medan inloggningen pågår. + Inloggning pågår… + Tryck för att fortsätta. + Inloggad! Google login kunde inte startas. - Vi har gjort för många försök att leverera en verifieringskod via SMS – Vänta lite och be om en ny om en minut. + Skriv in ett lösenord + \nDu kanske vill prova ett annat konto? Det var något som inte stämde vid uppkoppling till Google-kontot. - Det finns inget WordPress.com-konto som stämmer mot detta Google-konto. Stäng Logga in via Google. + Ett nätverksfel har inträffat. Kontrollera anslutningen och försök igen. Inloggad som Lyckas inte hitta ditt e-postprogram - Har du inget konto? %1$sRegistrera dig%2$s Skriv in en verifieringskod - Skriv in ett lösenord - Skriv in ett användarnamn + En dublett-webbplats har hittats. + Det går inte att lägga till denna webbplats. Den finns redan i appen. + Det gick inte att ansluta. Vi får fel 403 (förbjudet) när vi anropar XMLRPC-ändpunkten för din webbplats. Appen behöver detta för att kunna kommunicera med din webbplats. Kontakta webbhotellet för att lösa detta problem. + Det gick inte att ansluta. Din webbserver blockerar POST-anrop, som appen behöver för att kommunicera med din webbplats. Kontakta ditt webbhotell för att lösa detta problem. + Kontrollerar e-post + Kunde inte ansluta. Obligatoriska XML-RPC-metoder saknas på servern. + Kunde inte hämta din profil + Logga in igen för att fortsätta. + Glömt ditt lösenord? + Användarnamnet eller lösenordet som angavs är felaktigt + Ange en giltig epostadress + Ett fel uppstod + Autentisering krävs + Kontrollera att webbplatsens URL är giltig + HTTP-lösenord + HTTP-användarnamn + Ange en webbplats som ligger på WordPress.com eller en WordPress-webbplats på egen server som är ansluten till Jetpack + Registrerar med Google … + Alternativt: + Allmänt + \@%s + Logga in med ditt användarnamn. + Logga in genom att skriva din webbplatsadress. + Skicka ett nytt SMS med en kod till mig istället. + Vi har skickat ett SMS till telefonnumret som slutar på %s. Skriv in bekräftelsekoden from SMS;et. + Ange motsvarande lösenord för WordPress.com för att fortsätta med detta Google-konto. Denna fråga får du endast en gång. Logga in på WordPress.com för att dela innehållet. + Skriv in adressen för den WordPress-webbplats dit du vill dela innehållet. + Ett fel inträffade när standardwebbläsaren skulle öppnas. Välj en annan app: + Kan inte öppna länken + Skriv in ett användarnamn Logga in till ditt konto på WordPress.com för att nå inlägget. Ett fel inträffade när webbplatsen skulle läggas till. Felkod: %s Webbplatsadressen kontrolleras @@ -3486,25 +3533,15 @@ Language: sv_SE Vilket webbplatsadress har jag? Behöver du hjälp att hitta din webbplatsadress? Webbplatsadress - Skriv in adressen för den WordPress-webbplats dit du vill dela innehållet. \@%s Redan inloggad på WordPress.com Fortsätt - Anslut en webbplats Anslut ytterligare webbplats - Ange motsvarande lösenord för WordPress.com för att fortsätta med detta Google-konto. Denna fråga får du endast en gång. Skriv in ditt lösenord för WordPress.com. - Inte tillgänglig för närvarande. Ange ditt lösenord Begär e-postadress för inloggning Det verkar som om ditt lösenord inte stämmer. Dubbelkolla dina uppgifer och försök igen. Begär en verifieringskod via SMS. - Skicka ett nytt SMS med en kod till mig istället. Skicka mig en kod via SMS istället. - Vi har skickat ett SMS till telefonnumret som slutar på %s. Skriv in bekräftelsekoden from SMS;et. - Nästan där! Ange verifieringskoden för WordPress.com från din autentiseringsapp. - Logga in med ditt användarnamn. - Logga in genom att skriva din webbplatsadress. - Alternativt: Öppna e-posten Nästa Hantera din Jetpack-förstärkta webbplats när som helst – WordPress finns i din ficka. @@ -3512,35 +3549,75 @@ Language: sv_SE Håll koll på dina favoritwebbplatser och delta i diskussion där och när det passar dig. Se hur läsare från hela världen läser och interagerar med din webbplats – i direktsändning. Publicera från parkbänken. Blogga från bussen. Kommentera när du dricker kaffe. WordPress finns där du är. - Logga in - Hjälp - Lösenord - Användarnamn - Ange ditt lösenord istället + Du är redan inloggad till ditt konto hos WordPress.com. Du kan inte lägga till någon webbplats från WordPress.com som är kopplad till ett annat konto. + Försök igen + Logga ut Skicka länk + Inte tillgänglig för närvarande. Ange ditt lösenord + Loggar in + Ange ditt lösenord istället + E-postadress + Ångra Ogiltig verifieringskod Verifieringskod - E-postadress + Hjälp + Kasta bort + Logga in + Användarnamn + Lösenord + Utan titel + Inställningar + Idag + Avbryt + Äldre än en månad + Äldre än en vecka + Äldre än 2 dagar + Igår + Idag + Produkter + Detta år + Denna månad + Denna vecka + Produkt + Dölj detaljer + Fortsätt + Lär dig mer + Rabatt + Betalning + -%1$s%2$s + %1$s%2$s + WooCommerce + Ingen SMS-app hittades + Besökare + År + Månader + Veckor + Dagar + Logga in med ett annat konto + Inga WooCommerce-butiker + Ditt profilfoto + Ansluten butik + Ingen aktivitet denna period + Felbild + Intäkter + Misslyckades + Slutförd + Avbruten Support för WooCommerce Android %s alternativ ej markerat alternativ markerat Policyer från tredje part Cookie-policy Integritetspolicy - Skapad med kärlek av Automattic. %1$s Vi använder andra spårningsverktyg, inklusive några från tredje part. Läs om dessa verktyg och hur du kontrollerar dem. Läs integritetspolicyn Denna information hjälper oss att förbättra våra produkter, se till att marknadsföringen till dig är mer relevant, anpassa din upplevelse av WooCommerce och annat som finns beskrivet i vår integritetspolicy. Dela information med vårt analysverktyg om din användning av olika tjänster medan du är inloggad på ditt WordPress-konto Samla in information Integritetsinställningar - Inställningar Orderstatus Återbetalad - Avbruten Pausad - Slutförd - Misslyckades Inväntar betalning Behandlas Kunde inte lägga till notering @@ -3548,7 +3625,6 @@ Language: sv_SE Lägg till Skicka notering till kund via e-post Det gick inte att ändra ordern - Det gick inte att hämta noteringar Ordern har markerats som slutförd Markera ordern som slutförd Lägg till en ordernotering @@ -3557,7 +3633,6 @@ Language: sv_SE Visa fakturering Betalning godkänd Ordernoteringar - Privat Skapa en ordernotering Kundprofilsbild Kundnotering @@ -3582,70 +3657,32 @@ Language: sv_SE Inga ordrar Visa ordrar Visa order - Ingen aktivitet denna period - Totalt antal beställningar: %s - Felbild Det gick inte att hämta data - Intäkter Ordrar - Besökare - År - Månader - Veckor - Dagar - Logga in med ett annat konto - Inga WooCommerce-butiker - Ditt profilfoto - Ansluten butik - Läs %1$skonfigurationsinstruktionerna%2$s. - Denna app kräver Jetpack för att ansluta till din butik. - \@%s - Ange adressen till den WooCommerce-butik som du vill ansluta. Logga in med e-postadressen för ditt WordPress.com-konto för att hantera dina WooCommerce-butiker. - Du är redan inloggad till ditt konto hos WordPress.com. Du kan inte lägga till någon webbplats från WordPress.com som är kopplad till ett annat konto. - Kan inte öppna länken - Ingen SMS-app hittades Ingen app för e-post hittades Ingen telefonappen hittades - Ett fel inträffade när standardwebbläsaren skulle öppnas. Välj en annan app: Kan inte öppna länken %1$s at %2$s - Äldre än en månad - Äldre än en vecka - Äldre än 2 dagar - Igår - Idag - Produkter - Kasta bort - Detta år - Denna månad - Denna vecka - Idag - Produkt Ditt nätverk är inte tillgängligt. Kontrollera din data- eller WiFi-anslutning. Offline u2014 med cachade data - Lär dig mer - Avbryt - Utan titel - Fortsätt - Ångra - Försök igen - Dölj detaljer - Detaljer - Rabatt Delsumma - Momser - Betalning Frakt - -%1$s%2$s - %1$s%2$s + Totalt Ordrar Min butik - Logga ut - Loggar in Alla - Allmänt - WooCommerce + Denna app kräver Jetpack för att ansluta till din butik. + Detaljer + Momser + Skapad med kärlek av Automattic. %1$s + Ange adressen till den WooCommerce-butik som du vill ansluta. + Privat + Anslut en webbplats + Totalt antal beställningar: %s + Det gick inte att hämta noteringar + Läs %1$skonfigurationsinstruktionerna%2$s. + Nästan där! Ange verifieringskoden för WordPress.com från din autentiseringsapp. @string/date_timeframe_custom @string/date_timeframe_today diff --git a/WooCommerce/src/main/res/values-tr/strings.xml b/WooCommerce/src/main/res/values-tr/strings.xml index 1a1be477206..15927a46d8d 100644 --- a/WooCommerce/src/main/res/values-tr/strings.xml +++ b/WooCommerce/src/main/res/values-tr/strings.xml @@ -1,11 +1,47 @@ + Zarf + Kutu + Paket Ekleyin + Bunu yeni bir paket şablonu olarak kaydet + Yükseklik + Genişlik + Uzunluk + Paket türü + Kaydedildi + Kargo Şirketi + Özel + İade talep et + Alma tarihi zamanla + Gönderimi takip et + Mobil cihazınızdan nasıl yazdıracağınız hakkında bilgi edinin + Not: Yazdırılmış bir etiketi yeniden kullanmak hizmet koşullarımızın ihlalidir ve cezai suçlamalarla sonuçlanabilir. + Buradan gönderim etiketini yeniden yazdırabilir veya etiketin kağıt boyutunu değiştirebilirsiniz. + Gönderim etiketiniz yazdırmaya hazır + Üzgünüz, bu siparişi yalnızca web üzerinden düzenleyebilirsiniz, çünkü bu sipariş %1$s kullanıyor ve sitenizin para birimi şu:%2$s + Gönderim hizmeti + En hızlı + En ucuz + Satın Alma Etiketi + Satın Alma Etiketi · %1$s + Bu siparişi tamamlandı olarak işaretleyin ve müşteriyi bilgilendirin + Gönderim maliyeti + Sipariş ayrıntıları + Gönderi ayrıntıları + Mevcut gönderim ücretlerini görmek için paketinizin ölçülerini girin veya bir kargo paketi seçeneği seçin. + Gönderim ücretleri almak için bir paket seçin + Paket Seç + Zararlı ürünler veya tehlikeli materyaller mi gönderiyorsunuz? + Öğe kartını daraltın/genişletin + %1$s  ·  %2$s + Şuna göre sıralı: 1%s + Hayır Gelecekteki kampanyalar için seçimimi kaydet <b>Şunlar açısından iyi:</b> %s Hedef seç %s @@ -554,7 +590,7 @@ Language: tr Ödeme Alın Kod XXXX-XXXX-XXXX-XXXX biçiminde olmalıdır. Kod girin - Kupon + Kuponlar Temalar yüklenemedi. Yapılandırma tamamlandı Miktarı Güncellemeyi Geri Al @@ -3637,6 +3673,7 @@ Language: tr Vergiler Ödeme Gönderim + Toplam -%1$s%2$s %1$s%2$s Siparişler diff --git a/WooCommerce/src/main/res/values-zh-rCN/strings.xml b/WooCommerce/src/main/res/values-zh-rCN/strings.xml index d437ebb875d..c79685a1660 100644 --- a/WooCommerce/src/main/res/values-zh-rCN/strings.xml +++ b/WooCommerce/src/main/res/values-zh-rCN/strings.xml @@ -1,11 +1,47 @@ + 信封 + 箱子 + 添加包裹 + 将其保存为新的包裹模板 + 高度 + 宽度 + 长度 + 包裹类型 + 已保存 + 承运商 + 自定义 + 请求退款 + 预约取件 + 跟踪货物 + 了解如何从您的移动设备打印 + 注意:重复使用打印的标签违反了我们的服务条款,并可能导致刑事指控。 + 在此处,您可以再次打印运输标签或更改标签的纸张尺寸。 + 您的运输标签已可供打印 + 很抱歉,您只能在网页上编辑此订单,因为它使用的是 %1$s,而您站点的货币是 %2$s + 运输服务 + 速度最快 + 费用最低 + 购买标签 + 购买标签 · %1$s + 将订单标注为已完成并通知客户 + 运输费用 + 订单详细信息 + 配送详细信息 + 输入您的包裹尺寸或选择一个承运商包裹选项,查看适用的运费。 + 选择一个包裹以获取运费 + 选择一个包裹 + 您是否要运输危险品或危险物质? + 折叠/展开商品卡 + %1$s  ·  %2$s + 按 1%s 排序 + 保存我的选择,以备将来活动使用 <b>适合:</b>%s 选择目标 %s @@ -3637,6 +3673,7 @@ Language: zh_CN 税费 付款 配送 + 合计 -%1$s%2$s %1$s%2$s 订单 diff --git a/WooCommerce/src/main/res/values-zh-rTW/strings.xml b/WooCommerce/src/main/res/values-zh-rTW/strings.xml index 1dfc147d1ac..7127e50c04d 100644 --- a/WooCommerce/src/main/res/values-zh-rTW/strings.xml +++ b/WooCommerce/src/main/res/values-zh-rTW/strings.xml @@ -1,11 +1,47 @@ + 信封 + 包裝箱 + 新增包裹 + 將此儲存為新的包裹範本 + 高度 + 寬度 + 長度 + 包裹類型 + 已儲存 + 貨運商 + 自訂 + 要求退款 + 安排取貨 + 追蹤貨件 + 了解如何從行動裝置印製 + 請注意:若你重複使用已印製標籤,此行為將違反我們的服務條款,並可能會導致刑事責任。 + 你可以在這裡再次印製貨運標籤,或變更標籤的紙張大小。 + 你的貨運標籤已可供印製 + 很抱歉,你只能在網頁上編輯此訂單,這是因為此訂單使用「%1$s」,而貴網站採用的幣值為:%2$s + 貨運服務 + 最快速 + 最便宜 + 購買標籤 + 購買標籤 · %1$s + 將此訂單標示為完成並通知客戶 + 貨運費用 + 訂單詳細資料 + 貨運詳細資料 + 輸入包裹尺寸,或挑選貨運業者專用包裝選項,以查看適用的貨運費率。 + 選取包裹以取得貨運費率 + 選取包裹 + 你要寄送的貨件是否屬於有害或危險物品類別? + 收合/展開商品卡片 + %1$s  ·  %2$s + 排序依據:1%s + 儲存我的選取項目,供日後行銷活動使用 <b>適合:</b> %s 選取目標 %s @@ -554,7 +590,7 @@ Language: zh_TW 收取款項 序號必須採用 XXXX-XXXX-XXXX-XXXX 格式。 輸入序號 - 優惠券 + 折價券 無法載入佈景主題。 設定完成 已復原更新數量 @@ -3637,6 +3673,7 @@ Language: zh_TW 稅金 付款 運送方式 + 總計 -%1$s%2$s %1$s%2$s 訂單 diff --git a/WooCommerce/src/main/res/values/colors_base.xml b/WooCommerce/src/main/res/values/colors_base.xml index a19755ca585..15a64417c57 100644 --- a/WooCommerce/src/main/res/values/colors_base.xml +++ b/WooCommerce/src/main/res/values/colors_base.xml @@ -300,8 +300,8 @@ @color/white @color/woo_gray_6 @color/woo_gray_0 - @color/woo_gray_0 @color/woo_purple_0 + @color/blaze_blue Preview Edit ad - Shop now Details Audience Budget @@ -3980,7 +3989,10 @@ --> Change image Tagline + Tagline cannot be empty + Call to action Description + Description cannot be empty %d characters remaining Suggested by AI Invalid image @@ -4218,6 +4230,7 @@ Check out Remove %s from cart Product %s, Price %s + Variable Product %s, Price %s Product in cart %s, Price %s Cart Clear @@ -4289,6 +4302,8 @@ Popup menu with options. Swipe to navigate through items. It looks like you\'re not connected to the internet. Ensure your Wi-Fi is turned on. If you\'re using mobile data, make sure it\'s enabled in your device settings. + %1$d variations + Customer Orders diff --git a/WooCommerce/src/main/res/values/wc_colors_base.xml b/WooCommerce/src/main/res/values/wc_colors_base.xml index 0bc17dfdaff..9e65fc668be 100644 --- a/WooCommerce/src/main/res/values/wc_colors_base.xml +++ b/WooCommerce/src/main/res/values/wc_colors_base.xml @@ -101,6 +101,8 @@ #007017 #BBE0FA #055D9C - #FACFD2 + #0038FF #B32D2E + #FACFD2 + diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/model/ShippingLineDetailsTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/model/ShippingLineDetailsTest.kt new file mode 100644 index 00000000000..18b76328d4e --- /dev/null +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/model/ShippingLineDetailsTest.kt @@ -0,0 +1,66 @@ +package com.woocommerce.android.model + +import com.woocommerce.android.ui.orders.creation.shipping.toShippingLineDetails +import junit.framework.TestCase.assertEquals +import java.math.BigDecimal +import kotlin.test.Test +import kotlin.test.assertNotEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class ShippingLineDetailsTest { + private val defaultShippingMethods = List(3) { i -> + ShippingMethod( + id = "method$i", + title = "methodTitle$i" + ) + } + + private val defaultShippingLines = List(3) { i -> + Order.ShippingLine( + itemId = i.toLong(), + methodId = "method$i", + methodTitle = "shippingLineTitle$i", + totalTax = BigDecimal.TEN * i.toBigDecimal(), + total = BigDecimal.ZERO + ) + } + + @Test + fun `toShippingLineDetails should return null for empty list`() { + val shippingLines = emptyList() + val result = shippingLines.toShippingLineDetails(defaultShippingMethods) + assertNull(result) + } + + @Test + fun `toShippingLineDetails should use method title from the shipping method field`() { + val result = defaultShippingLines.toShippingLineDetails(defaultShippingMethods) + assertNotNull(result) + result.forEachIndexed { index, shippingLineDetails -> + // Use the method title from Order.ShippingLine as name + assertEquals(shippingLineDetails.name, "shippingLineTitle$index") + // Use the method title from ShippingMethod as the method title + assertEquals(shippingLineDetails.shippingMethod!!.title, "methodTitle$index") + } + } + + @Test + fun `toShippingLineDetails should skip shipping lines with null methodId`() { + val shippingLines = defaultShippingLines.toMutableList() + shippingLines.add( + // Because this shipping line methodId is null it should be discarded + Order.ShippingLine( + itemId = 33L, + methodId = null, + methodTitle = "shippingLineDiscarded", + totalTax = BigDecimal.TEN, + total = BigDecimal.ZERO + ) + ) + val result = shippingLines.toShippingLineDetails(defaultShippingMethods) + assertNotNull(result) + assertNotEquals(result.size, shippingLines.size) + assertEquals(result.size, defaultShippingLines.size) + } +} diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/UpdateAnalyticsHubStatsTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/UpdateAnalyticsHubStatsTest.kt index 44a98a58550..273c6eace45 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/UpdateAnalyticsHubStatsTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/UpdateAnalyticsHubStatsTest.kt @@ -383,6 +383,10 @@ internal class UpdateAnalyticsHubStatsTest : BaseUnitTest() { @Test fun `when data store allows new stats fetch, then request data with ForceNew strategy`() = testBlocking { + // Given + whenever(repository.fetchVisitorsData(testRangeSelection, ForceNew)) + .doReturn(testVisitorsResult) + // When sut(testRangeSelection, this) @@ -409,6 +413,8 @@ internal class UpdateAnalyticsHubStatsTest : BaseUnitTest() { analyticsUpdateDataStore = analyticsDataStore, analyticsRepository = repository ) + whenever(repository.fetchVisitorsData(testRangeSelection, Saved)) + .doReturn(testVisitorsResult) // When sut(testRangeSelection, this) @@ -437,6 +443,8 @@ internal class UpdateAnalyticsHubStatsTest : BaseUnitTest() { analyticsUpdateDataStore = analyticsDataStore, analyticsRepository = repository ) + whenever(repository.fetchVisitorsData(testCustomRangeSelection, Saved)) + .doReturn(testVisitorsResult) // When sut(testCustomRangeSelection, this) @@ -457,6 +465,8 @@ internal class UpdateAnalyticsHubStatsTest : BaseUnitTest() { analyticsUpdateDataStore = analyticsDataStore, analyticsRepository = repository ) + whenever(repository.fetchVisitorsData(testRangeSelection, ForceNew)) + .doReturn(testVisitorsResult) // When sut(testRangeSelection, this, true) @@ -490,6 +500,8 @@ internal class UpdateAnalyticsHubStatsTest : BaseUnitTest() { analyticsUpdateDataStore = analyticsDataStore, analyticsRepository = repository ) + whenever(repository.fetchVisitorsData(testRangeSelection, Saved)) + .doReturn(testVisitorsResult) // When sut(testRangeSelection, this, false) @@ -539,6 +551,8 @@ internal class UpdateAnalyticsHubStatsTest : BaseUnitTest() { analyticsUpdateDataStore = analyticsDataStore, analyticsRepository = repository ) + whenever(repository.fetchVisitorsData(eq(testRangeSelection), any())) + .doReturn(testVisitorsResult) // When sut(testRangeSelection, this) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/BlazeRepositoryTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/BlazeRepositoryTest.kt index af42c4a247e..73257ddd62e 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/BlazeRepositoryTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/BlazeRepositoryTest.kt @@ -128,6 +128,7 @@ class BlazeRepositoryTest : BaseUnitTest() { productId = 1, tagLine = "", description = "", + ctaText = "", campaignImage = AD_IMAGE, budget = DEFAULT_BUDGET, targetingParameters = EMPTY_TARGETING_PARAMETERS, diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/payment/BlazeCampaignPaymentSummaryViewModelTests.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/payment/BlazeCampaignPaymentSummaryViewModelTests.kt index e10ddcc2409..ac7ee52525c 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/payment/BlazeCampaignPaymentSummaryViewModelTests.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/payment/BlazeCampaignPaymentSummaryViewModelTests.kt @@ -28,6 +28,7 @@ class BlazeCampaignPaymentSummaryViewModelTests : BaseUnitTest() { productId = 0L, tagLine = "", description = "", + ctaText = "", campaignImage = BlazeRepository.BlazeCampaignImage.LocalImage("test"), budget = Budget( totalBudget = 10f, diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModelTests.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModelTests.kt index c71fd63d30d..da65b4dd2be 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModelTests.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/blaze/creation/preview/BlazeCampaignCreationPreviewViewModelTests.kt @@ -12,6 +12,7 @@ import com.woocommerce.android.ui.blaze.Device import com.woocommerce.android.ui.blaze.Interest import com.woocommerce.android.ui.blaze.Language import com.woocommerce.android.ui.blaze.Location +import com.woocommerce.android.ui.blaze.creation.ad.BlazeCampaignCreationEditAdViewModel.EditAdResult import com.woocommerce.android.ui.blaze.creation.preview.BlazeCampaignCreationPreviewViewModel.AdDetailsUi import com.woocommerce.android.ui.blaze.creation.targets.BlazeTargetType import com.woocommerce.android.util.CurrencyFormatter @@ -45,6 +46,7 @@ class BlazeCampaignCreationPreviewViewModelTests : BaseUnitTest() { productId = PRODUCT_ID, tagLine = "", description = "", + ctaText = "", budget = BlazeRepository.Budget( totalBudget = 10f, spentBudget = 0f, @@ -81,6 +83,7 @@ class BlazeCampaignCreationPreviewViewModelTests : BaseUnitTest() { on { observeInterests() } doReturn flowOf(interests) on { observeLanguages() } doReturn flowOf(languages) on { observeObjectives() } doReturn flowOf(objectives) + onBlocking { fetchAdSuggestions(any()) } doReturn Result.success(emptyList()) } private val analyticsTracker: AnalyticsTrackerWrapper = mock() private lateinit var viewModel: BlazeCampaignCreationPreviewViewModel @@ -105,6 +108,7 @@ class BlazeCampaignCreationPreviewViewModelTests : BaseUnitTest() { BlazeRepository.AiSuggestionForAd( tagLine = "Ad suggestion 1", description = "Ad suggestion 1 description", + ctaText = "Shop now" ) ) setup { @@ -197,9 +201,10 @@ class BlazeCampaignCreationPreviewViewModelTests : BaseUnitTest() { val newTagline = "New tagline" val newDescription = "New description" + val newCtaText = "New CTA" val newImage = BlazeCampaignImage.LocalImage("new_image") val state = viewModel.viewState.runAndCaptureValues { - viewModel.onAdUpdated(newTagline, newDescription, newImage) + viewModel.onAdUpdated(EditAdResult(newTagline, newDescription, newImage, newCtaText)) }.last() val adDetailsUi = state.adDetails as AdDetailsUi.AdDetails diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/IsStoreCurrencyMisMatchTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/IsStoreCurrencyMisMatchTest.kt new file mode 100644 index 00000000000..cc0ab8ebe38 --- /dev/null +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/IsStoreCurrencyMisMatchTest.kt @@ -0,0 +1,39 @@ +package com.woocommerce.android.ui.orders + +import com.woocommerce.android.tools.SelectedSite +import com.woocommerce.android.viewmodel.BaseUnitTest +import junit.framework.TestCase.assertTrue +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import org.wordpress.android.fluxc.model.WCSettingsModel +import org.wordpress.android.fluxc.store.WooCommerceStore +import kotlin.test.assertFalse + +@OptIn(ExperimentalCoroutinesApi::class) +class IsStoreCurrencyMisMatchTest : BaseUnitTest() { + private val wooCommerceStore: WooCommerceStore = mock() + private val selectedSite: SelectedSite = mock() + val wcSettingsModel = mock { + on { currencyCode }.thenReturn("USD") + } + private val isStoreCurrencyMatch: IsStoreCurrencyMatch = IsStoreCurrencyMatch(wooCommerceStore, selectedSite) + + @Test + fun `when order currency is different than store, then return data model with correct data`() = testBlocking { + whenever(wooCommerceStore.getSiteSettings(selectedSite.get())).thenReturn(wcSettingsModel) + + assertFalse(isStoreCurrencyMatch("INR").isMatch) + assertThat(isStoreCurrencyMatch("INR").storeCurrency).isEqualTo("USD") + } + + @Test + fun `when order currency is same as store, then enable edit menu in order creation`() = testBlocking { + whenever(wooCommerceStore.getSiteSettings(selectedSite.get())).thenReturn(wcSettingsModel) + + assertTrue(isStoreCurrencyMatch("USD").isMatch) + assertThat(isStoreCurrencyMatch("USD").storeCurrency).isEqualTo("USD") + } +} diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderDetailViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderDetailViewModelTest.kt index 82cc76776e6..810b6cc7251 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderDetailViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderDetailViewModelTest.kt @@ -26,6 +26,7 @@ import com.woocommerce.android.tools.NetworkStatus import com.woocommerce.android.tools.ProductImageMap import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.common.giftcard.GiftCardRepository +import com.woocommerce.android.ui.orders.OrderNavigationTarget.EditOrder import com.woocommerce.android.ui.orders.OrderNavigationTarget.PreviewReceipt import com.woocommerce.android.ui.orders.OrderNavigationTarget.StartWooShippingLabelCreationFlow import com.woocommerce.android.ui.orders.creation.shipping.GetShippingMethodsWithOtherValue @@ -184,6 +185,7 @@ class OrderDetailViewModelTest : BaseUnitTest() { private val getShippingMethodsWithOtherValue: GetShippingMethodsWithOtherValue = mock() private val refreshShippingMethods: RefreshShippingMethods = mock() + private val isStoreCurrencyMatch: IsStoreCurrencyMatch = mock() private fun createViewModel() { createViewModel(newSavedState = savedState) @@ -212,6 +214,7 @@ class OrderDetailViewModelTest : BaseUnitTest() { paymentReceiptHelper, analyticsTracker, refreshShippingMethods, + isStoreCurrencyMatch, getShippingMethodsWithOtherValue, ) ) @@ -1648,6 +1651,9 @@ class OrderDetailViewModelTest : BaseUnitTest() { doReturn(order).whenever(orderDetailRepository).fetchOrderById(any()) doReturn(false).whenever(orderDetailRepository).fetchOrderNotes(any()) doReturn(false).whenever(addonsRepository).containsAddonsFrom(any()) + whenever(isStoreCurrencyMatch.invoke(any())).thenReturn( + CurrencyMatchResult(isMatch = true, storeCurrency = "USD") + ) viewModel.start() // When @@ -2427,4 +2433,59 @@ class OrderDetailViewModelTest : BaseUnitTest() { assertThat(viewModel.event.value).isInstanceOf(OrderNavigationTarget.StartShippingLabelCreationFlow::class.java) } + + @Test + fun `given order and store currency mismatch, when edit clicked, then trigger snackbar event`() = testBlocking { + // Given + whenever(orderDetailRepository.getOrderById(any())).thenReturn(order) + whenever(orderDetailRepository.fetchOrderById(any())).thenReturn(order) + whenever(orderDetailRepository.fetchOrderNotes(any())).thenReturn(false) + whenever(addonsRepository.containsAddonsFrom(any())).thenReturn(false) + whenever(isStoreCurrencyMatch.invoke(any())).thenReturn( + CurrencyMatchResult(isMatch = false, storeCurrency = "USD") + ) + viewModel.start() + + // When + viewModel.onEditClicked() + + assertThat(viewModel.event.value).isInstanceOf(ShowSnackbar::class.java) + } + + @Test + fun `given order and store currency mismatch, when edit clicked, then track proper event`() = testBlocking { + // Given + whenever(orderDetailRepository.getOrderById(any())).thenReturn(order) + whenever(orderDetailRepository.fetchOrderById(any())).thenReturn(order) + whenever(orderDetailRepository.fetchOrderNotes(any())).thenReturn(false) + whenever(addonsRepository.containsAddonsFrom(any())).thenReturn(false) + whenever(isStoreCurrencyMatch.invoke(any())).thenReturn( + CurrencyMatchResult(isMatch = false, storeCurrency = "USD") + ) + viewModel.start() + + // When + viewModel.onEditClicked() + + verify(orderDetailTracker).trackOrderAndStoreCurrencyMismatchWhenEditButtonTapped() + } + + @Test + fun `given order and store currency are same, when edit clicked, then trigger EditOrder event`() = testBlocking { + // Given + whenever(orderDetailRepository.getOrderById(any())).thenReturn(order) + whenever(orderDetailRepository.fetchOrderById(any())).thenReturn(order) + whenever(orderDetailRepository.fetchOrderNotes(any())).thenReturn(false) + whenever(addonsRepository.containsAddonsFrom(any())).thenReturn(false) + whenever(isStoreCurrencyMatch.invoke(any())).thenReturn( + CurrencyMatchResult(isMatch = true, storeCurrency = "USD") + ) + viewModel.start() + + // When + viewModel.onEditClicked() + + assertThat(viewModel.event.value).isNotInstanceOf(ShowSnackbar::class.java) + assertThat(viewModel.event.value).isInstanceOf(EditOrder::class.java) + } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt index c0f0ce40f80..9ce8facdeb3 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt @@ -18,6 +18,7 @@ import com.woocommerce.android.model.Address import com.woocommerce.android.model.FeatureFeedbackSettings import com.woocommerce.android.model.Order import com.woocommerce.android.model.ShippingMethod +import com.woocommerce.android.model.WooPlugin import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.barcodescanner.BarcodeScanningTracker import com.woocommerce.android.ui.feedback.FeedbackRepository @@ -31,7 +32,7 @@ import com.woocommerce.android.ui.orders.creation.configuration.ProductRules import com.woocommerce.android.ui.orders.creation.navigation.OrderCreateEditNavigationTarget import com.woocommerce.android.ui.orders.creation.product.discount.CurrencySymbolFinder import com.woocommerce.android.ui.orders.creation.shipping.GetShippingMethodsWithOtherValue -import com.woocommerce.android.ui.orders.creation.shipping.ShippingLineDetails +import com.woocommerce.android.ui.orders.creation.shipping.ShippingLineSection import com.woocommerce.android.ui.orders.creation.shipping.ShippingUpdateResult import com.woocommerce.android.ui.orders.creation.taxes.GetAddressFromTaxRate import com.woocommerce.android.ui.orders.creation.taxes.GetTaxRatesInfoDialogViewState @@ -131,6 +132,12 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { any() ) } doReturn MutableLiveData(emptyOrder) + on { + getLiveData( + key = eq("plugins_information"), + initialValue = any>(), + ) + } doReturn MutableLiveData(HashMap()) } createUpdateOrderUseCase = mock { onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(Order.getEmptyOrder(Date(), Date()))) @@ -191,8 +198,24 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { prefs = mock() mapFeeLineToCustomAmountUiModel = mock() totalsHelper = mock() - getShippingMethodsWithOtherValue = mock() - feedbackRepository = mock() + getShippingMethodsWithOtherValue = mock { + onBlocking { invoke() } doReturn flowOf( + listOf( + ShippingMethod( + id = "other", + title = "Other" + ) + ) + ) + } + feedbackRepository = mock { + onBlocking { + getFeatureFeedbackSetting(eq(FeatureFeedbackSettings.Feature.ORDER_SHIPPING_LINES)) + } doReturn FeatureFeedbackSettings( + feature = FeatureFeedbackSettings.Feature.ORDER_SHIPPING_LINES, + feedbackState = FeatureFeedbackSettings.FeedbackState.UNANSWERED + ) + } fetchProductBySKU = mock() } @@ -1884,14 +1907,14 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { whenever(getShippingMethodsWithOtherValue.invoke()).doReturn(getShippingMethodsResult) createSut() - var shippingDetails: List? = null - sut.shippingLineList.observeForever { - shippingDetails = it + var shippingSection: ShippingLineSection? = null + sut.shippingLineSection.observeForever { + shippingSection = it } - assertThat(shippingDetails).isNotNull - assertThat(shippingDetails!!.size).isEqualTo(shippingLines.size) - val shippingMethod = shippingDetails!!.firstOrNull { it.shippingMethod?.id == shippingMethodId } + assertThat(shippingSection).isNotNull + assertThat(shippingSection!!.shippingLines.size).isEqualTo(shippingLines.size) + val shippingMethod = shippingSection!!.shippingLines.firstOrNull { it.shippingMethod?.id == shippingMethodId } assertThat(shippingMethod).isNotNull assertThat(shippingMethod!!.shippingMethod!!.title).isEqualTo(shippingMethodTitle) } @@ -1921,14 +1944,14 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { whenever(getShippingMethodsWithOtherValue.invoke()).doReturn(getShippingMethodsResult) createSut() - var shippingDetails: List? = null - sut.shippingLineList.observeForever { - shippingDetails = it + var shippingSection: ShippingLineSection? = null + sut.shippingLineSection.observeForever { + shippingSection = it } - assertThat(shippingDetails).isNotNull - assertThat(shippingDetails!!.size).isEqualTo(shippingLines.size) - val shippingMethod = shippingDetails!!.firstOrNull { it.shippingMethod?.id == shippingMethodId } + assertThat(shippingSection).isNotNull + assertThat(shippingSection!!.shippingLines.size).isEqualTo(shippingLines.size) + val shippingMethod = shippingSection!!.shippingLines.firstOrNull { it.shippingMethod?.id == shippingMethodId } assertThat(shippingMethod).isNull() } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModelTest.kt index f5ab1b3e7fa..8784cef1117 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModelTest.kt @@ -2,11 +2,12 @@ package com.woocommerce.android.ui.orders.wooshippinglabels.packages import androidx.lifecycle.SavedStateHandle import com.woocommerce.android.R -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.CustomPackageCreationData import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageSelected import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageType import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.ShowPackageTypeDialog import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.ViewState +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.FetchCarrierPackagesFromStore +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.FetchSavedPackagesFromStore import com.woocommerce.android.viewmodel.BaseUnitTest import com.woocommerce.android.viewmodel.MultiLiveEvent import com.woocommerce.android.viewmodel.ResourceProvider @@ -21,8 +22,9 @@ import org.mockito.kotlin.whenever class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { private lateinit var sut: WooShippingLabelPackageCreationViewModel - private val savedStateHandle: SavedStateHandle = SavedStateHandle() private val resourceProvider: ResourceProvider = mock() + private val fetchSavedPackages: FetchSavedPackagesFromStore = mock() + private val fetchCarrierPackages: FetchCarrierPackagesFromStore = mock() @Before fun setUp() { @@ -35,7 +37,14 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { whenever( resourceProvider.getString(R.string.woo_shipping_labels_package_creation_tab_saved) ).thenReturn("Saved") - sut = WooShippingLabelPackageCreationViewModel(savedStateHandle, resourceProvider) + + whenever(fetchSavedPackages()).thenReturn(emptyList()) + sut = WooShippingLabelPackageCreationViewModel( + SavedStateHandle(), + resourceProvider, + fetchSavedPackages, + fetchCarrierPackages + ) } @Test @@ -57,9 +66,9 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { sut.onSavePackageChanged(true) sut.onPackageTypeSelected(PackageType.ENVELOPE) - sut.onAddPackageClick() + sut.onAddCustomPackageClick() - assertThat(lastEvent).isEqualTo(PackageSelected(customPackageData)) + assertThat(lastEvent).isEqualTo(PackageSelected(customPackageData.asPackageData)) } @Test @@ -124,4 +133,167 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { assertThat(lastViewState?.customPackageCreationData?.saveAsTemplate).isEqualTo(newSaveAsTemplate) } + + @Test + fun `onSavedPackageSelected selects only one package at a time`() = testBlocking { + var lastViewState: ViewState? = null + val package1 = PackageData( + type = PackageType.BOX, + name = "Package 1", + description = "Description 1", + length = "10", + width = "10", + height = "10", + isSelected = false + ) + val package2 = PackageData( + type = PackageType.ENVELOPE, + name = "Package 2", + description = "Description 2", + length = "20", + width = "20", + height = "20", + isSelected = false + ) + whenever(fetchSavedPackages()).thenReturn(listOf(package1, package2)) + + sut = WooShippingLabelPackageCreationViewModel( + SavedStateHandle(), + resourceProvider, + fetchSavedPackages, + fetchCarrierPackages + ) + sut.viewState.observeForever { lastViewState = it } + sut.onSavedPackageSelected(package1, true) + + val selectedPackages = lastViewState?.savedPackageSelection?.packages?.filter { it.isSelected } + assertThat(selectedPackages).isNotNull + assertThat(selectedPackages).size().isEqualTo(1) + assertThat(selectedPackages?.first()).isEqualTo(package1.copy(isSelected = true)) + } + + @Test + fun `onCarrierPackageSelected selects only one package at a time`() = testBlocking { + var lastViewState: ViewState? = null + val carrier = Carrier(id = "dhl", name = "DHL Express", logoRes = R.drawable.dhl_logo) + val package1 = PackageData( + type = PackageType.BOX, + name = "Package 1", + description = "Description 1", + length = "10", + width = "10", + height = "10", + isSelected = false + ) + val package2 = PackageData( + type = PackageType.ENVELOPE, + name = "Package 2", + description = "Description 2", + length = "20", + width = "20", + height = "20", + isSelected = false + ) + val carrierPackages = mapOf( + carrier to listOf( + CarrierPackageGroup( + groupName = "Group 1", + packages = listOf(package1, package2) + ) + ) + ) + whenever(fetchCarrierPackages()).thenReturn(carrierPackages) + + sut = WooShippingLabelPackageCreationViewModel( + SavedStateHandle(), + resourceProvider, + fetchSavedPackages, + fetchCarrierPackages + ) + sut.viewState.observeForever { lastViewState = it } + sut.onCarrierPackageSelected(package1, true) + + val selectedPackages = lastViewState?.carrierPackageSection?.carrierPackages?.values?.flatten()?.flatMap { + it.packages + }?.filter { it.isSelected } + assertThat(selectedPackages).isNotNull + assertThat(selectedPackages).size().isEqualTo(1) + assertThat(selectedPackages?.first()).isEqualTo(package1.copy(isSelected = true)) + } + + @Test + @Suppress("LongMethod") + fun `onCarrierPackageSelected selects only one package at a time with multiple carriers`() = testBlocking { + var lastViewState: ViewState? = null + val carrier1 = Carrier(id = "dhl", name = "DHL Express", logoRes = R.drawable.dhl_logo) + val carrier2 = Carrier(id = "usps", name = "USPS", logoRes = R.drawable.usps_logo) + val package1 = PackageData( + type = PackageType.BOX, + name = "Package 1 - Carrier 1", + description = "Description 1", + length = "10", + width = "10", + height = "10", + isSelected = false + ) + val package2 = PackageData( + type = PackageType.ENVELOPE, + name = "Package 2 - Carrier 1", + description = "Description 2", + length = "20", + width = "20", + height = "20", + isSelected = false + ) + val package3 = PackageData( + type = PackageType.BOX, + name = "Package 1 - Carrier 2", + description = "Description 3", + length = "30", + width = "30", + height = "30", + isSelected = false + ) + val package4 = PackageData( + type = PackageType.ENVELOPE, + name = "Package 2 - Carrier 2", + description = "Description 4", + length = "40", + width = "40", + height = "40", + isSelected = false + ) + val carrierPackages = mapOf( + carrier1 to listOf( + CarrierPackageGroup( + groupName = "Group 1", + packages = listOf(package1, package2) + ) + ), + carrier2 to listOf( + CarrierPackageGroup( + groupName = "Group 2", + packages = listOf(package3, package4) + ) + ) + ) + whenever(fetchCarrierPackages()).thenReturn(carrierPackages) + + sut = WooShippingLabelPackageCreationViewModel( + SavedStateHandle(), + resourceProvider, + fetchSavedPackages, + fetchCarrierPackages + ) + sut.viewState.observeForever { lastViewState = it } + sut.onCarrierPackageSelected(package1, true) + sut.onCarrierPackageSelected(package2, true) + + val selectedPackages = lastViewState?.carrierPackageSection?.carrierPackages?.values?.flatten()?.flatMap { + it.packages + }?.filter { it.isSelected } + assertThat(selectedPackages).isNotNull + assertThat(selectedPackages).size().isEqualTo(1) + assertThat(selectedPackages?.first()).isEqualTo(package2.copy(isSelected = true)) + } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingErrorCtaClickHandlerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingErrorCtaClickHandlerTest.kt index ca649f8c832..e1ca82b5665 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingErrorCtaClickHandlerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingErrorCtaClickHandlerTest.kt @@ -358,50 +358,10 @@ class CardReaderOnboardingErrorCtaClickHandlerTest : BaseUnitTest() { ) } - @Test - fun `given wpcom site, when invoked with WC_PAY_NOT_SETUP, then OpenWpComWebView returned`() = - testBlocking { - // GIVEN - whenever(siteModel.isWPCom).thenReturn(true) - val adminUrl = "mywebsite.com" - whenever(siteModel.adminUrl).thenReturn(adminUrl) - - // WHEN - val result = handler(CardReaderOnboardingCTAErrorType.WC_PAY_NOT_SETUP) - - // THEN - assertThat(result).isEqualTo( - CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenWpComWebView( - url = "$adminUrl/admin.php?page=wc-admin&path=%2Fpayments%2Foverview" - ) - ) - } - - @Test - fun `given wpcomatomic site, when invoked with WC_PAY_NOT_SETUP, then OpenWpComWebView returned`() = - testBlocking { - // GIVEN - whenever(siteModel.isWPComAtomic).thenReturn(true) - val adminUrl = "mywebsite.com" - whenever(siteModel.adminUrl).thenReturn(adminUrl) - - // WHEN - val result = handler(CardReaderOnboardingCTAErrorType.WC_PAY_NOT_SETUP) - - // THEN - assertThat(result).isEqualTo( - CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenWpComWebView( - url = "$adminUrl/admin.php?page=wc-admin&path=%2Fpayments%2Foverview" - ) - ) - } - @Test fun `given non wpcom site, when invoked with WC_PAY_NOT_SETUP, then OpenGenericWebView returned`() = testBlocking { // GIVEN - whenever(siteModel.isWPCom).thenReturn(false) - whenever(siteModel.isWPComAtomic).thenReturn(false) val adminUrl = "mywebsite.com" whenever(siteModel.adminUrl).thenReturn(adminUrl) @@ -410,7 +370,7 @@ class CardReaderOnboardingErrorCtaClickHandlerTest : BaseUnitTest() { // THEN assertThat(result).isEqualTo( - CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenGenericWebView( + CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenBrowser( url = "$adminUrl/admin.php?page=wc-admin&path=%2Fpayments%2Foverview" ) ) @@ -432,50 +392,10 @@ class CardReaderOnboardingErrorCtaClickHandlerTest : BaseUnitTest() { ) } - @Test - fun `given wpcom site, when invoked with STRIPE_ACCOUNT_OVERDUE_REQUIREMENTS, then OpenWpComWebView returned`() = - testBlocking { - // GIVEN - whenever(siteModel.isWPCom).thenReturn(true) - val adminUrl = "mywebsite.com" - whenever(siteModel.adminUrl).thenReturn(adminUrl) - - // WHEN - val result = handler(CardReaderOnboardingCTAErrorType.STRIPE_ACCOUNT_OVERDUE_REQUIREMENTS) - - // THEN - assertThat(result).isEqualTo( - CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenWpComWebView( - url = "$adminUrl/admin.php?page=wc-admin&path=%2Fpayments%2Foverview" - ) - ) - } - - @Test - fun `given wpcom atomic site, when invoked with STRIPE_ACCOUNT_OVERDUE_REQUIREMENTS, then OpenWpComWebView returned`() = - testBlocking { - // GIVEN - whenever(siteModel.isWPComAtomic).thenReturn(true) - val adminUrl = "mywebsite.com" - whenever(siteModel.adminUrl).thenReturn(adminUrl) - - // WHEN - val result = handler(CardReaderOnboardingCTAErrorType.STRIPE_ACCOUNT_OVERDUE_REQUIREMENTS) - - // THEN - assertThat(result).isEqualTo( - CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenWpComWebView( - url = "$adminUrl/admin.php?page=wc-admin&path=%2Fpayments%2Foverview" - ) - ) - } - @Test fun `given non wpcom site, when invoked with STRIPE_ACCOUNT_OVERDUE_REQUIREMENTS, then OpenGenericWebView returned`() = testBlocking { // GIVEN - whenever(siteModel.isWPCom).thenReturn(false) - whenever(siteModel.isWPComAtomic).thenReturn(false) val adminUrl = "mywebsite.com" whenever(siteModel.adminUrl).thenReturn(adminUrl) @@ -484,7 +404,7 @@ class CardReaderOnboardingErrorCtaClickHandlerTest : BaseUnitTest() { // THEN assertThat(result).isEqualTo( - CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenGenericWebView( + CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenBrowser( url = "$adminUrl/admin.php?page=wc-admin&path=%2Fpayments%2Foverview" ) ) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt index 16a28b4a6ad..5a4cdd60b15 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt @@ -312,7 +312,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { testBlocking { val url = "url" whenever(errorClickHandler.invoke(CardReaderOnboardingCTAErrorType.WC_PAY_NOT_SETUP)) - .thenReturn(CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenWpComWebView(url)) + .thenReturn(CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenBrowser(url)) val viewModel = createVM( CardReaderOnboardingFragmentArgs( @@ -328,7 +328,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { .actionButtonActionPrimary.invoke() assertThat(viewModel.event.value).isEqualTo( - CardReaderOnboardingEvent.NavigateToUrlInWPComWebView(url) + CardReaderOnboardingEvent.NavigateToUrlInBrowser(url) ) } @@ -337,7 +337,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { testBlocking { val url = "url" whenever(errorClickHandler.invoke(CardReaderOnboardingCTAErrorType.WC_PAY_NOT_SETUP)) - .thenReturn(CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenGenericWebView(url)) + .thenReturn(CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenBrowser(url)) val viewModel = createVM( CardReaderOnboardingFragmentArgs( @@ -353,7 +353,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { .actionButtonActionPrimary.invoke() assertThat(viewModel.event.value).isEqualTo( - CardReaderOnboardingEvent.NavigateToUrlInGenericWebView(url) + CardReaderOnboardingEvent.NavigateToUrlInBrowser(url) ) } @@ -362,7 +362,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { testBlocking { val url = "url" whenever(errorClickHandler.invoke(CardReaderOnboardingCTAErrorType.STRIPE_ACCOUNT_OVERDUE_REQUIREMENTS)) - .thenReturn(CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenWpComWebView(url)) + .thenReturn(CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenBrowser(url)) val viewModel = createVM( CardReaderOnboardingFragmentArgs( @@ -379,7 +379,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { .actionButtonPrimary!!.action.invoke() assertThat(viewModel.event.value).isEqualTo( - CardReaderOnboardingEvent.NavigateToUrlInWPComWebView(url) + CardReaderOnboardingEvent.NavigateToUrlInBrowser(url) ) } @@ -388,7 +388,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { testBlocking { val url = "url" whenever(errorClickHandler.invoke(CardReaderOnboardingCTAErrorType.STRIPE_ACCOUNT_OVERDUE_REQUIREMENTS)) - .thenReturn(CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenGenericWebView(url)) + .thenReturn(CardReaderOnboardingErrorCtaClickHandler.Reaction.OpenBrowser(url)) val viewModel = createVM( CardReaderOnboardingFragmentArgs( @@ -404,7 +404,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { .actionButtonPrimary!!.action.invoke() assertThat(viewModel.event.value).isEqualTo( - CardReaderOnboardingEvent.NavigateToUrlInGenericWebView(url) + CardReaderOnboardingEvent.NavigateToUrlInBrowser(url) ) } @@ -623,7 +623,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { (viewModel.viewStateData.value as UnsupportedErrorState.WcPayInCountry) .onLearnMoreActionClicked.invoke() - val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInGenericWebView + val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInBrowser assertThat(event.url).isEqualTo(AppUrls.WOOCOMMERCE_LEARN_MORE_ABOUT_PAYMENTS) } @@ -637,7 +637,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { (viewModel.viewStateData.value as UnsupportedErrorState.Country) .onLearnMoreActionClicked.invoke() - val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInGenericWebView + val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInBrowser assertThat(event.url).isEqualTo(AppUrls.WOOCOMMERCE_LEARN_MORE_ABOUT_PAYMENTS) } @@ -690,7 +690,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { (viewModel.viewStateData.value as UnsupportedErrorState.Country).onLearnMoreActionClicked.invoke() - val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInGenericWebView + val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInBrowser assertThat(event.url).isEqualTo(AppUrls.STRIPE_LEARN_MORE_ABOUT_PAYMENTS) } @@ -706,7 +706,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { (viewModel.viewStateData.value as UnsupportedErrorState.Country).onLearnMoreActionClicked.invoke() - val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInGenericWebView + val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInBrowser assertThat(event.url).isEqualTo(AppUrls.WOOCOMMERCE_LEARN_MORE_ABOUT_PAYMENTS) } @@ -720,7 +720,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { (viewModel.viewStateData.value as UnsupportedErrorState.StripeAccountInUnsupportedCountry) .onLearnMoreActionClicked.invoke() - val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInGenericWebView + val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInBrowser assertThat(event.url).isEqualTo(AppUrls.WOOCOMMERCE_LEARN_MORE_ABOUT_PAYMENTS) } @@ -1113,7 +1113,7 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { (viewModel.viewStateData.value as CashOnDeliveryDisabledState) .onLearnMoreActionClicked.invoke() - val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInGenericWebView + val event = viewModel.event.value as CardReaderOnboardingEvent.NavigateToUrlInBrowser assertThat(event.url).isEqualTo(AppUrls.WOOCOMMERCE_LEARN_MORE_ABOUT_PAYMENTS) } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModelTest.kt index dcac585e0e8..769f54493b1 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModelTest.kt @@ -8,6 +8,7 @@ import com.woocommerce.android.ui.woopos.common.data.WooPosGetProductById import com.woocommerce.android.ui.woopos.home.ParentToChildrenEvent import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender import com.woocommerce.android.ui.woopos.home.WooPosParentToChildrenEventReceiver +import com.woocommerce.android.ui.woopos.home.items.WooPosItemNavigationData import com.woocommerce.android.ui.woopos.util.WooPosCoroutineTestRule import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsTracker @@ -76,7 +77,11 @@ class WooPosCartViewModelTest { // WHEN parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product.remoteId + ) + ) ) // THEN @@ -101,7 +106,11 @@ class WooPosCartViewModelTest { val states = sut.state.captureValues() parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product.remoteId + ) + ) ) // WHEN @@ -156,7 +165,11 @@ class WooPosCartViewModelTest { val states = sut.state.captureValues() parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product.remoteId + ) + ) ) // THEN @@ -185,7 +198,11 @@ class WooPosCartViewModelTest { val states = sut.state.captureValues() parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product.remoteId + ) + ) ) sut.onUIEvent(WooPosCartUIEvent.CheckoutClicked) @@ -197,6 +214,7 @@ class WooPosCartViewModelTest { assertThat(toolbar.isClearAllButtonVisible).isFalse() } + @Suppress("LongMethod") @Test fun `given non empty cart in process, when 2 items added and the first removed and third item added, then third will have item number 2`() = runTest { @@ -228,10 +246,18 @@ class WooPosCartViewModelTest { // WHEN parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product1.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product1.remoteId + ) + ) ) parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product2.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product2.remoteId + ) + ) ) sut.onUIEvent( @@ -247,7 +273,11 @@ class WooPosCartViewModelTest { ) parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product3.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product3.remoteId + ) + ) ) // THEN @@ -285,7 +315,11 @@ class WooPosCartViewModelTest { val states = sut.state.captureValues() parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product.remoteId + ) + ) ) // WHEN @@ -314,7 +348,11 @@ class WooPosCartViewModelTest { val states = sut.state.captureValues() parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product.remoteId + ) + ) ) // WHEN @@ -354,7 +392,11 @@ class WooPosCartViewModelTest { val states = sut.state.captureValues() parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product.remoteId + ) + ) ) // WHEN @@ -384,7 +426,11 @@ class WooPosCartViewModelTest { // WHEN parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product.remoteId + ) + ) ) // THEN @@ -407,7 +453,11 @@ class WooPosCartViewModelTest { val states = sut.state.captureValues() parentToChildrenEventsMutableFlow.emit( - ParentToChildrenEvent.ItemClickedInProductSelector(product.remoteId) + ParentToChildrenEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product.remoteId + ) + ) ) // WHEN diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosItemsViewModelTest.kt similarity index 94% rename from WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt rename to WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosItemsViewModelTest.kt index 4adf8293fc5..ad4b8805f4f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosItemsViewModelTest.kt @@ -6,6 +6,7 @@ import com.woocommerce.android.ui.products.ProductTestUtils import com.woocommerce.android.ui.woopos.home.ChildToParentEvent import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender import com.woocommerce.android.ui.woopos.home.items.WooPosItem +import com.woocommerce.android.ui.woopos.home.items.WooPosItemNavigationData import com.woocommerce.android.ui.woopos.home.items.WooPosItemsUIEvent import com.woocommerce.android.ui.woopos.home.items.WooPosItemsViewModel import com.woocommerce.android.ui.woopos.home.items.WooPosItemsViewState @@ -29,7 +30,7 @@ import kotlin.test.Test import kotlin.test.assertTrue @ExperimentalCoroutinesApi -class WooPosProductsViewModelTest { +class WooPosItemsViewModelTest { @Rule @JvmField @@ -249,7 +250,11 @@ class WooPosProductsViewModelTest { viewModel.viewState.test { // THEN verify(fromChildToParentEventSender).sendToParent( - ChildToParentEvent.ItemClickedInProductSelector(product.id) + ChildToParentEvent.ItemClickedInProductSelector( + WooPosItemNavigationData.SimpleProductData( + id = product.id + ) + ) ) cancelAndConsumeRemainingEvents() } @@ -794,6 +799,45 @@ class WooPosProductsViewModelTest { verify(fromChildToParentEventSender).sendToParent(ChildToParentEvent.ProductsDialogInfoIconClicked) } + @Test + fun `given variable products from data source, when view model created, then items list updated correctly`() = runTest { + // GIVEN + val products = listOf( + ProductTestUtils.generateProduct( + productId = 1, + productName = "Product 1", + amount = "10.0", + productType = "simple", + isDownloadable = false, + ), + ProductTestUtils.generateProduct( + productId = 2, + productName = "Product 2", + amount = "20.0", + productType = "variable", + isDownloadable = false, + isVariable = true + ).copy(firstImageUrl = "https://test.com") + ) + + whenever(productsDataSource.loadSimpleProducts(any())).thenReturn( + flowOf( + WooPosProductsDataSource.ProductsResult.Remote( + Result.success(products) + ) + ) + ) + + // WHEN + val viewModel = createViewModel() + viewModel.viewState.test { + // THEN + val value = awaitItem() as WooPosItemsViewState.Content + + assertThat(value.items.filterIsInstance().size).isEqualTo(1) + } + } + private fun createViewModel() = WooPosItemsViewModel( productsDataSource, diff --git a/build.gradle b/build.gradle index b5df01ef33e..8a338fb7a89 100644 --- a/build.gradle +++ b/build.gradle @@ -10,6 +10,7 @@ plugins { alias(libs.plugins.android.library) apply false alias(libs.plugins.android.test) apply false alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose).apply(false) alias(libs.plugins.kotlin.parcelize) apply false alias(libs.plugins.google.dagger.hilt) apply false alias(libs.plugins.androidx.navigation.safeargs) apply false @@ -34,7 +35,7 @@ allprojects { tasks.withType(KotlinCompile).all { kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + jvmTarget = libs.versions.java.get() allWarningsAsErrors = true freeCompilerArgs += [ "-opt-in=kotlin.RequiresOptIn", diff --git a/fastlane/Fastfile b/fastlane/Fastfile index b593c94a000..69deaa37dcf 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -15,7 +15,7 @@ WEAR_APP = 'WooCommerce-Wear' PROJECT_ROOT_FOLDER = File.dirname(File.expand_path(__dir__)) VERSIONS_CATALOG_FILE = File.join(PROJECT_ROOT_FOLDER, 'gradle/libs.versions.toml') BUILD_PRODUCTS_PATH = File.join(PROJECT_ROOT_FOLDER, 'artifacts') -PROTOTYPE_BUILD_DOMAIN = 'https://d2twmm2nzpx3bg.cloudfront.net' +PROTOTYPE_BUILD_DOMAIN = 'https://cdn.a8c-ci.services' # The `android_download_translations` action joins the `RES_DIR_PATH` with `PROJECT_ROOT_FOLDER`, so we don't want to # add `PROJECT_ROOT_FOLDER` to the beginning of this path RES_DIR_PATH = File.join('WooCommerce', 'src', 'main', 'res') @@ -906,7 +906,7 @@ platform :android do app_package_name: APP_PACKAGE_NAME, app_apk_path: 'WooCommerce/build/outputs/apk/vanilla/debug/WooCommerce-vanilla-debug.apk', tests_apk_path: 'WooCommerce/build/outputs/apk/androidTest/vanilla/debug/WooCommerce-vanilla-debug-androidTest.apk', - use_tests_in_classes: "#{APP_PACKAGE_NAME}.screenshots.ScreenshotTest", + use_tests_in_classes: "#{APP_PACKAGE_NAME}.e2e.tests.screenshot.ScreenshotTest", reinstall_app: false, # By default, don't clear previous because we differentiate between light # and dark mode diff --git a/fastlane/metadata/PlayStoreStrings.pot b/fastlane/metadata/PlayStoreStrings.pot index 1911ca2d722..55da5a6d434 100644 --- a/fastlane/metadata/PlayStoreStrings.pot +++ b/fastlane/metadata/PlayStoreStrings.pot @@ -16,17 +16,16 @@ msgid "In this update, we’ve made a few small bug fixes and enhancements to en msgstr "" #. translators: Release notes for this version to be displayed in the Play Store. Limit to 500 characters including spaces and commas! -msgctxt "release_note_210" +msgctxt "release_note_211" msgid "" -"21.0:\n" -"Enjoy a smoother experience with improved design throughout the app. Plus, now your product images load faster and look even better with new AVIF format support. Update now for a cleaner, sharper WooCommerce app experience!\n" -"\n" +"21.1:\n" +"Our latest update brings key enhancements to streamline your WooCommerce experience! We’ve fixed editing permissions for orders in different currencies, optimized the payments hub view, enabled easy receipt sharing via Google SMS, and fixed date range selection to correctly use your timezone. Enjoy smoother operations!\n" msgstr "" -msgctxt "release_note_209" +msgctxt "release_note_210" msgid "" -"20.9:\n" -"\n" +"21.0:\n" +"Enjoy a smoother experience with improved design throughout the app. Plus, now your product images load faster and look even better with new AVIF format support. Update now for a cleaner, sharper WooCommerce app experience!\n" "\n" msgstr "" diff --git a/fastlane/metadata/android/ar/changelogs/default.txt b/fastlane/metadata/android/ar/changelogs/default.txt new file mode 100644 index 00000000000..0afa24d9e26 --- /dev/null +++ b/fastlane/metadata/android/ar/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +يطرح آخر تحديث لدينا تحسينات أساسية لتبسيط تجربتك على WooCommerce! لقد أصلحنا صلاحيات التحرير للطلبات بمختلف العملات، وقمنا بتحسين طريقة عرض مركز المدفوعات وتمكين مشاركة الإيصالات بسهولة عبر الرسائل النصية القصيرة على غوغل وأصلحنا اختيار نطاق التاريخ لاستخدام منطقتك الزمنية بشكل صحيح. استمتع بعمليات تشغيل أكثر سلاسة! diff --git a/fastlane/metadata/android/de-DE/changelogs/default.txt b/fastlane/metadata/android/de-DE/changelogs/default.txt new file mode 100644 index 00000000000..0e4780673b6 --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +Mit unserem neuesten Update stehen wichtige Verbesserungen zur Optimierung deines WooCommerce-Erlebnisses bereit! Wir haben die Bearbeitungsberechtigungen für Bestellungen in verschiedenen Währungen angepasst, die Hub-Ansicht für Zahlungen optimiert, das einfache Teilen von Belegen über Google SMS aktiviert und die Auswahl des Datumsbereichs korrigiert, sodass deine Zeitzone verwendet wird. Genieße die reibungsloseren Abläufe! diff --git a/fastlane/metadata/android/en-US/changelogs/default.txt b/fastlane/metadata/android/en-US/changelogs/default.txt index a739194ce52..71f78412b04 100644 --- a/fastlane/metadata/android/en-US/changelogs/default.txt +++ b/fastlane/metadata/android/en-US/changelogs/default.txt @@ -1,2 +1 @@ -Enjoy a smoother experience with improved design throughout the app. Plus, now your product images load faster and look even better with new AVIF format support. Update now for a cleaner, sharper WooCommerce app experience! - +Our latest update brings key enhancements to streamline your WooCommerce experience! We’ve fixed editing permissions for orders in different currencies, optimized the payments hub view, enabled easy receipt sharing via Google SMS, and fixed date range selection to correctly use your timezone. Enjoy smoother operations! diff --git a/fastlane/metadata/android/es-ES/changelogs/default.txt b/fastlane/metadata/android/es-ES/changelogs/default.txt new file mode 100644 index 00000000000..44379c853a6 --- /dev/null +++ b/fastlane/metadata/android/es-ES/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +Nuestra última actualización trae mejoras clave para agilizar tu experiencia de WooCommerce. Hemos corregido los permisos de edición para pedidos en distintas divisas, optimizado la vista del centro de pagos, facilitado el uso compartido de recibos a través de Google SMS y corregido la selección del intervalo de fechas para utilizar correctamente la zona horaria. Disfruta de un funcionamiento más fluido. diff --git a/fastlane/metadata/android/fr-FR/changelogs/default.txt b/fastlane/metadata/android/fr-FR/changelogs/default.txt new file mode 100644 index 00000000000..d150da74121 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1 : +Notre dernière mise à jour apporte des améliorations clés pour rationaliser votre expérience WooCommerce ! Nous avons corrigé les droits d’édition pour les commandes dans d’autres devises, optimisé la vue du centre de paiements, donné la possibilité de partager facilement les reçus via Google SMS et corrigé la sélection de plage de dates pour bien utiliser votre fuseau horaire. Profitez d’opérations plus fluides ! diff --git a/fastlane/metadata/android/id/changelogs/default.txt b/fastlane/metadata/android/id/changelogs/default.txt new file mode 100644 index 00000000000..5689bedb0bb --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +Pembaruan terkini kami menghadirkan penyempurnaan penting untuk memperlancar pengalaman WooCommerce Anda! Kami memperbaiki izin pengeditan untuk pesanan yang menggunakan mata uang berbeda, mengoptimalkan tampilan hub pembayaran, mengaktifkan fitur berbagi tanda terima dengan mudah via Google SMS, dan memperbaiki pemilihan rentang tanggal agar sesuai dengan zona waktu Anda. Nikmati pengoperasian yang lebih baik! diff --git a/fastlane/metadata/android/it-IT/changelogs/default.txt b/fastlane/metadata/android/it-IT/changelogs/default.txt new file mode 100644 index 00000000000..3140f887211 --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +Il nostro ultimo aggiornamento contiene miglioramenti importanti per snellire l'esperienza WooCommerce. Abbiamo corretto i permessi di modifica per gli ordini in valute diverse, ottimizzato la visualizzazione dell'hub dei pagamenti, consentito una facile condivisione delle ricevute tramite SMS Google e definito la selezione dell'intervallo di date per poter utilizzare correttamente il proprio fuso orario. Goditi un funzionamento più fluido. diff --git a/fastlane/metadata/android/iw-IL/changelogs/default.txt b/fastlane/metadata/android/iw-IL/changelogs/default.txt new file mode 100644 index 00000000000..8e48db3bbcc --- /dev/null +++ b/fastlane/metadata/android/iw-IL/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +בעדכון האחרון שלנו הוספנו שיפורים מהותיים כדי לאפשר חוויית שימוש יעילה ב-WooCommerce! תיקנו את עריכת ההרשאות בהזמנות עם מטבעות שונים, מיטבנו את התצוגה של מרכז התשלומים, הפעלנו שיתוף קל לקבלות דרך Google SMS ותיקנו את הבחירה בטווח התאריכים כדי לאפשר שימוש תקין באזור הזמן שבחרת. חוויית התפעול עכשיו חלקה יותר! diff --git a/fastlane/metadata/android/ja-JP/changelogs/default.txt b/fastlane/metadata/android/ja-JP/changelogs/default.txt new file mode 100644 index 00000000000..d6c154edb35 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +最新のアップデートでは、WooCommerce エクスペリエンスを合理化する重要な機能強化が導入されました。 異なる通貨での注文における編集パーミッションを修正し、支払いハブのビューも最適化しました。また Google SMS で領収書を簡単に共有できるようにしたほか、日付範囲の選択を修正してタイムゾーンを正しく使用できるようにしました。 よりスムーズになった操作をご利用ください。 diff --git a/fastlane/metadata/android/ko-KR/changelogs/default.txt b/fastlane/metadata/android/ko-KR/changelogs/default.txt new file mode 100644 index 00000000000..6428dfc3ccc --- /dev/null +++ b/fastlane/metadata/android/ko-KR/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +최신 업데이트에서는 우커머스 경험을 간소화해 주는 주요 개선 사항을 제공합니다! 다른 통화로 된 주문에 대한 편집 권한이 수정되었고, 결제 허브 보기가 최적화되었으며, Google SMS를 통해 영수증을 쉽게 공유할 수 있고, 시간대를 올바르게 사용할 수 있도록 날짜 범위 선택 기능이 수정되었습니다. 작업이 더 원활해졌습니다! diff --git a/fastlane/metadata/android/nl-NL/changelogs/default.txt b/fastlane/metadata/android/nl-NL/changelogs/default.txt new file mode 100644 index 00000000000..32e10c1ba60 --- /dev/null +++ b/fastlane/metadata/android/nl-NL/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +Onze nieuwste update voert belangrijke verbeteringen door om je WooCommerce-ervaring te stroomlijnen! We hebben de bewerkingstoestemmingen voor bestellingen in verschillende valuta's hersteld, de hubweergave voor betalingen geoptimaliseerd, het delen van betalingsbewijzen via Google SMS mogelijk gemaakt en de selectie van datumbereiken hersteld zodat je tijdzone correct wordt weergeven. Geniet van een verbeterd systeem! diff --git a/fastlane/metadata/android/pt-BR/changelogs/default.txt b/fastlane/metadata/android/pt-BR/changelogs/default.txt new file mode 100644 index 00000000000..38a4eb680c4 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +Esta última atualização traz melhorias importantes para simplificar sua experiência no WooCommerce. Corrigimos a edição de permissões para pedidos em moedas diferentes, otimizamos a visualização do hub de pagamentos, ativamos o compartilhamento fácil de recibos pelo serviço de mensagens do Google e corrigimos a seleção de intervalo de datas para usar o seu fuso horário. Aproveite operações mais eficientes! diff --git a/fastlane/metadata/android/ru-RU/changelogs/default.txt b/fastlane/metadata/android/ru-RU/changelogs/default.txt new file mode 100644 index 00000000000..f572839191c --- /dev/null +++ b/fastlane/metadata/android/ru-RU/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +В нашем последнем обновлении реализованы важнейшие усовершенствования, которые сделают вашу работу с WooCommerce ещё удобнее! Мы исправили разрешения на редактирование заказов в разных валютах, оптимизировали представление платёжного центра, подключили удобный обмен квитанциями через Google SMS и исправили выбор диапазона дат, чтобы ваш часовой пояс отображался правильно. Желаем вам приятной работы! diff --git a/fastlane/metadata/android/sv-SE/changelogs/default.txt b/fastlane/metadata/android/sv-SE/changelogs/default.txt new file mode 100644 index 00000000000..1b52466a91d --- /dev/null +++ b/fastlane/metadata/android/sv-SE/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +Vår senaste uppdatering innehåller viktiga förbättringar för att effektivisera din WooCommerce-upplevelse. Vi har fixat redigeringsbehörigheter för beställningar i olika valutor, optimerat betalningshubbvyn, möjliggjort enkel delning av kvitton via Google SMS och åtgärdat datumintervallsvalet för korrekt användning av din tidszon. Ta del av smidigare hantering. diff --git a/fastlane/metadata/android/tr-TR/changelogs/default.txt b/fastlane/metadata/android/tr-TR/changelogs/default.txt new file mode 100644 index 00000000000..4297181de85 --- /dev/null +++ b/fastlane/metadata/android/tr-TR/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +En son güncellememiz WooCommerce deneyiminizi daha da kolaylaştırmak için önemli geliştirmeler getiriyor! Farklı para birimlerindeki siparişler için düzenleme izinlerini düzelttik, ödeme merkezi görünümünü optimize ettik, Google SMS aracılığıyla kolay makbuz paylaşımını etkinleştirdik ve saat diliminizi doğru şekilde kullanmak için tarih aralığı seçimini düzelttik. Daha sorunsuz işlemlerin keyfini çıkarın! diff --git a/fastlane/metadata/android/zh-CN/changelogs/default.txt b/fastlane/metadata/android/zh-CN/changelogs/default.txt new file mode 100644 index 00000000000..1de85b657e6 --- /dev/null +++ b/fastlane/metadata/android/zh-CN/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +我们的最新更新带来了重要的功能增强,可简化您的 WooCommerce 体验! 我们修复了不同币种订单的编辑权限,优化了付款中心视图,通过 Google 短信简化了收据共享流程,并修复了日期范围选择以便正确使用您的时区。 享受更顺畅的操作! diff --git a/fastlane/metadata/android/zh-TW/changelogs/default.txt b/fastlane/metadata/android/zh-TW/changelogs/default.txt new file mode 100644 index 00000000000..49500961b1f --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/default.txt @@ -0,0 +1,2 @@ +21.1: +我們的最新更新帶來重要強化功能,可簡化你的 WooCommerce 體驗! 我們修正了不同幣別訂單的編輯權限、將付款中心檢視畫面最佳化、啟用了透過 Google 簡訊輕鬆分享收據的功能,並且將日期範圍選取功能修正為正確時區設定。 享受更順暢的操作流程! diff --git a/fastlane/resources/values/strings.xml b/fastlane/resources/values/strings.xml index e25840f4fd7..9d831fdb431 100644 --- a/fastlane/resources/values/strings.xml +++ b/fastlane/resources/values/strings.xml @@ -694,7 +694,7 @@ Select a coupon -%1$s Coupon (%1$s) - Coupon + Coupons Coupons applied Increase product quantity Decrease product quantity @@ -1065,6 +1065,7 @@ Session page views Move to trash Do you want to move this order to the trash? + Sorry, you can only edit this order on the web, as it uses %1$s, and your site\'s currency is %2$s + + Custom + Carrier + Saved + Package type + Length + Width + Height + Save this as a new package template + Add Package + Box + Envelope diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7b87b0fa4cb..6cb4df8f5fa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,12 +10,11 @@ androidx-browser = '1.5.0' androidx-camera = '1.2.3' androidx-cardview = '1.0.0' androidx-compose-bom = '2024.04.00' -androidx-compose-compiler = '1.5.9' androidx-constraintlayout-compose = '1.0.1' androidx-constraintlayout-main = '2.1.4' androidx-core-main = '1.13.1' androidx-core-splashscreen = '1.0.1' -androidx-datastore = '1.1.0' +androidx-datastore = '1.0.0' # Higher versions of the DataStore library are presenting crashes, refer to peaMlT-XN before upgrading it. androidx-fragment = '1.8.2' androidx-hilt = '1.2.0' androidx-lifecycle = '2.7.0' @@ -70,12 +69,13 @@ google-services = '4.4.0' google-zxing = '3.5.3' gravatar = '0.2.0' jackson-databind = '2.12.7.1' +java = '11' jetty-webapp = '9.4.51.v20230217' json-path = '2.9.0' junit = '4.13.2' -kotlin = '1.9.22' +kotlin = '2.0.21' kotlinx-coroutines = '1.8.1' -ksp = '1.9.22-1.0.17' +ksp = '2.0.21-1.0.27' mockito-inline = '4.6.1' mockito-kotlin = '4.0.0' mpandroidchart = 'v3.1.0' @@ -86,7 +86,7 @@ stripe-terminal = '3.7.1' tinder-statemachine = '0.2.0' wiremock = '2.26.3' wordpress-aztec = 'v2.1.4' -wordpress-fluxc = '2.99.1' +wordpress-fluxc = 'trunk-cc17141a0e910d5b808ba6bbfb4b7d393d3517a0' wordpress-login = '1.19.0' wordpress-libaddressinput = '0.0.2' wordpress-mediapicker = '0.3.1' @@ -246,6 +246,7 @@ google-dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "goo google-protobuf = { id = "com.google.protobuf", version.ref = "google-protobuf-plugin" } google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } sentry = { id = "io.sentry.android.gradle", version.ref = "sentry" } diff --git a/libs/cardreader/build.gradle b/libs/cardreader/build.gradle index 6a1203bf7e9..4a082ede46f 100644 --- a/libs/cardreader/build.gradle +++ b/libs/cardreader/build.gradle @@ -21,8 +21,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility libs.versions.java.get() + targetCompatibility libs.versions.java.get() } } diff --git a/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/CardReaderManager.kt b/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/CardReaderManager.kt index 136d6f02f82..bddf554af87 100644 --- a/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/CardReaderManager.kt +++ b/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/CardReaderManager.kt @@ -61,6 +61,8 @@ interface CardReaderManager { enum class SimulatorUpdateFrequency { NEVER, ALWAYS, + LOW_BATTERY_ERROR, + LOW_BATTERY_SUCCEED_CONNECT, RANDOM } } diff --git a/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/internal/wrappers/TerminalWrapper.kt b/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/internal/wrappers/TerminalWrapper.kt index f3aa07fe50b..96c138f7a70 100644 --- a/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/internal/wrappers/TerminalWrapper.kt +++ b/libs/cardreader/src/main/java/com/woocommerce/android/cardreader/internal/wrappers/TerminalWrapper.kt @@ -109,6 +109,10 @@ internal class TerminalWrapper { return when (updateFrequency) { CardReaderManager.SimulatorUpdateFrequency.NEVER -> SimulateReaderUpdate.NONE CardReaderManager.SimulatorUpdateFrequency.ALWAYS -> SimulateReaderUpdate.REQUIRED + CardReaderManager.SimulatorUpdateFrequency.LOW_BATTERY_ERROR -> SimulateReaderUpdate.LOW_BATTERY + CardReaderManager.SimulatorUpdateFrequency.LOW_BATTERY_SUCCEED_CONNECT -> { + SimulateReaderUpdate.LOW_BATTERY_SUCCEED_CONNECT + } CardReaderManager.SimulatorUpdateFrequency.RANDOM -> SimulateReaderUpdate.RANDOM } } diff --git a/libs/commons/build.gradle b/libs/commons/build.gradle index a0d38063d6a..90a85c52ca1 100644 --- a/libs/commons/build.gradle +++ b/libs/commons/build.gradle @@ -13,10 +13,7 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' + sourceCompatibility libs.versions.java.get() + targetCompatibility libs.versions.java.get() } } diff --git a/libs/iap/build.gradle b/libs/iap/build.gradle index 0fcddd4cc9c..e116e9b8001 100644 --- a/libs/iap/build.gradle +++ b/libs/iap/build.gradle @@ -20,8 +20,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility libs.versions.java.get() + targetCompatibility libs.versions.java.get() } } diff --git a/quicklogin/build.gradle b/quicklogin/build.gradle index c2d921eba06..777990b5d42 100644 --- a/quicklogin/build.gradle +++ b/quicklogin/build.gradle @@ -66,8 +66,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility libs.versions.java.get() + targetCompatibility libs.versions.java.get() } buildFeatures { diff --git a/version.properties b/version.properties index 64c050b19ab..7e3d6267e14 100644 --- a/version.properties +++ b/version.properties @@ -1,2 +1,2 @@ -versionName=21.0-rc-1 -versionCode=623 \ No newline at end of file +versionName=21.1 +versionCode=627 \ No newline at end of file