Chủ đề này trình bày cách di chuyển từ Thư viện Google Play Billing 4 hoặc 5 sang Thư viện Google Play Billing 6 và cách sử dụng các tính năng mới dành cho gói thuê bao.
Để biết danh sách đầy đủ các thay đổi trong phiên bản 6.0.0, hãy tham khảo ghi chú phát hành.
Tổng quan
Thư viện Google Play Billing 6 được xây dựng dựa trên các tính năng mới đã ra mắt trong phiên bản 5 dành cho gói thuê bao, đồng thời bổ sung một số điểm cải tiến. Các tính năng này cung cấp cho bạn thêm cách để bán gói thuê bao, giảm chi phí vận hành mà không cần tạo và quản lý số lượng SKU ngày càng tăng.
Để biết thêm thông tin về các tính năng mới đã ra mắt trong Thư viện Play Billing 5, vui lòng xem phần Thay đổi gần đây đối với gói thuê bao trong Play Console.
Bản nâng cấp tương thích ngược cho Thư viện Play Billing
Tất cả sản phẩm thuê bao hiện tại đã được tự động chuyển đổi sang mô hình mới này trong bản phát hành tháng 5 năm 2022 của Thư viện Play Billing 5 và nền tảng mới cho gói thuê bao. Điều này nghĩa là bạn sẽ có một danh mục tương thích với các phiên bản mới của Thư viện Play Billing mà không cần phải thực hiện bất cứ thay đổi nào đối với cấu hình sản phẩm thuê bao. Để biết thêm thông tin về cách chuyển đổi SKU gói thuê bao thành gói thuê bao tương thích ngược, vui lòng xem phần Xử lý gói thuê bao cũ trong bài viết trên trang Trợ giúp của Play Console.
Các phiên bản cũ của ứng dụng sẽ vẫn hoạt động
Nếu bạn có danh mục gói thuê bao tương thích ngược, thì tất cả các phiên bản hiện có của ứng dụng sẽ vẫn hoạt động như dự kiến đối với các sản phẩm đó. Các giao dịch mua sản phẩm tính phí một lần cũng sẽ tiếp tục hoạt động mà không gặp vấn đề trong các phiên bản cũ.
Nếu đang áp dụng những phương thức không được dùng nữa (chẳng hạn như querySkuDetailsAsync()
), ứng dụng của bạn sẽ không thể bán gói ưu đãi hoặc gói cơ bản nào không có khả năng tương thích ngược. Bạn có thể đọc về các ưu đãi có khả năng tương thích ngược trong bài viết có liên quan trên Trung tâm trợ giúp của Play Console.
Nâng cấp Thư viện Play Billing lên phiên bản 5 hoặc 6
Thư viện Play Billing phiên bản 5 và 6 bao gồm những phương thức không được dùng nữa (querySkuDetailsAsync
và BillingFlowParams.Builder.setSkuDetails
), các phương thức này lấy SkuDetails
làm tham số luồng thanh toán. Theo đó, bạn có thể chuyển dần sang Thư viện Play Billing phiên bản 6 bằng cách lên kế hoạch cho các giai đoạn di chuyển.
Đối với bước đầu tiên trong quá trình di chuyển, bạn chỉ cần cập nhật phiên bản thư viện, giữ nguyên danh mục và phần phụ trợ, sau đó kiểm thử ứng dụng trong khi vẫn áp dụng các phương thức không dùng nữa. Nếu bạn không dùng queryPurchases
, launchPriceChangeFlow
hoặc setVrPurchaseFlow
, thì mã này sẽ vẫn hoạt động đúng như dự tính. Sau đó, bạn có thể lặp lại để áp dụng đầy đủ các tính năng mới được phát hành vào tháng 5 năm 2022 dành cho gói thuê bao.
Nếu từng sử dụng các tính năng này trong quá trình di chuyển Thư viện Google Play Billing phiên bản 5, bạn có thể chuyển trực tiếp đến các phần có nhãn Cập nhật Thư viện Google Play Billing rồi Thay đổi giao dịch mua gói thuê bao của người dùng. Nếu bắt đầu từ phiên bản trước đó hoặc chưa áp dụng đầy đủ các tính năng mới, bạn có thể đọc các bước di chuyển đầy đủ sau đây để tìm hiểu cách áp dụng các tính năng đó.
Các bước di chuyển đầy đủ
Tạo gói thuê bao mới trong danh mục sản phẩm phụ trợ
Bằng cách sử dụng API Play Developer Console hoặc API Nhà phát triển Play, giờ đây, bạn có thể thiết lập một gói thuê bao bao gồm nhiều gói cơ bản, mỗi gói có nhiều ưu đãi. Các gói ưu đãi có mô hình định giá và cách thiết lập tính đủ điều kiện một cách linh hoạt. Bạn có thể tạo ưu đãi trong suốt vòng đời của thuê bao bằng cách sử dụng nhiều gói trả trước và gói tự động gia hạn.
Bạn nên tạo sản phẩm mới theo cấu trúc thực thể trong nền tảng mới cho gói thuê bao để tích hợp Thư viện Play Billing 6 trước khi di chuyển ứng dụng. Bạn có thể hợp nhất các sản phẩm trùng lặp trong danh mục cũ có cùng lợi ích về quyền trong một gói thuê bao, đồng thời sử dụng các cấu hình của ưu đãi và gói cơ bản để đại diện cho tất cả các lựa chọn mà bạn muốn cung cấp. Để biết thêm thông tin về nội dung đề xuất này, hãy xem phần Xử lý gói thuê bao cũ trong bài viết trên trang Trợ giúp của Play Console.
Sau bản phát hành tháng 5 năm 2022, bạn không nên sửa đổi các sản phẩm thuê bao đã chuyển đổi mà nên giữ nguyên sản phẩm để bán kèm theo những phiên bản ứng dụng sử dụng các phương thức không dùng nữa (ví dụ: querySkuDetailsAsync()
). Đừng áp dụng những thay đổi có thể ảnh hưởng đến các bản dựng cũ này.
Quá trình chuyển đổi khiến các sản phẩm thuê bao trong danh mục của bạn trước tháng 5 năm 2022 ở chế độ chỉ có thể đọc để tránh những thay đổi do nhầm lẫn. Đây là những thay đổi có khả năng dẫn đến các vấn đề với chức năng tích hợp hiện có. Bạn có thể thực hiện các thay đổi đối với những gói thuê bao này, nhưng sẽ có những tác động có thể ảnh hưởng đến giao diện người dùng và các chức năng tích hợp phụ trợ:
Trên giao diện người dùng, các phiên bản ứng dụng dùng
querySkuDetailsAsync()
để lấy thông tin chi tiết về sản phẩm thuê bao chỉ có thể bán các ưu đãi và gói cơ bản có khả năng tương thích ngược. Đồng thời, do chỉ có một cách kết hợp giữa ưu đãi và gói cơ bản có khả năng tương thích ngược, nên nếu bạn thêm các ưu đãi hoặc gói mới vào gói thuê bao đã chuyển đổi, thì các phiên bản cũ này của ứng dụng sẽ không bán được các ưu đãi hoặc gói cơ bản bổ sung mới.Trên phần phụ trợ, nếu chỉnh sửa các gói thuê bao đã chuyển đổi trong giao diện người dùng Play Console, bạn sẽ không thể quản lý các gói thuê bao đó bằng điểm cuối
inappproducts
nếu đang gọi điểm cuối cho mục đích này. Bạn cũng nên di chuyển sang điểm cuối mới của trạng thái mua gói thuê bao (purchases.subscriptionsv2.get
) để quản lý các giao dịch mua những gói thuê bao này, bởi vì điểm cuối cũ của trạng thái mua (purchases.subscriptions.get
) chỉ trả về dữ liệu cần thiết để xử lý các giao dịch mua ưu đãi và gói cơ bản có khả năng tương thích ngược. Hãy đọc phần Quản lý trạng thái mua gói thuê bao để biết thêm thông tin.
Quản lý danh mục gói thuê bao phụ trợ bằng API mới
Nếu tự động quản lý danh mục sản phẩm thuê bao của mình bằng API Nhà phát triển Google Play, bạn cần sử dụng các điểm cuối mới giúp xác định sản phẩm thuê bao để tạo và quản lý các gói thuê bao, gói cơ bản và ưu đãi. Hãy đọc Hướng dẫn về các tính năng của gói thuê bao tháng 5 năm 2022 để tìm hiểu thêm về những thay đổi đối với API danh mục sản phẩm của bản phát hành này.
Để di chuyển mô-đun tự động giúp quản lý danh mục sản phẩm cho gói thuê bao Google Play Billing, hãy thay thế API inappproducts
bằng Subscription Publishing API (API phát hành gói thuê bao) mới để quản lý và phát hành danh mục gói thuê bao của bạn. Có 3 điểm cuối mới:
Monetization.subscriptions
để quản lý các sản phẩm thuê bao.Monetization.basePlans
để quản lý gói cơ bản của gói thuê bao.Monetization.offers
để quản lý ưu đãi của gói cơ bản.
Các điểm cuối mới này có tất cả chức năng cần thiết để tận dụng mọi tính năng mới trong danh mục của bạn: gói cơ bản và thẻ ưu đãi, tính năng nhắm mục tiêu theo vùng, gói trả trước, v.v..
Bạn vẫn nên sử dụng API inappproducts
để quản lý danh mục sản phẩm trong ứng dụng cho các sản phẩm áp dụng hình thức mua hàng một lần.
Các phiên bản ứng dụng sử dụng phương thức không dùng nữa (ví dụ: querySkuDetailsAsync()
) sẽ không thể bán bất kỳ ưu đãi hoặc gói cơ bản nào không có khả năng tương thích ngược. Bạn có thể đọc về các ưu đãi có khả năng tương thích ngược tại đây.
Cập nhật Thư viện Google Play Billing
Sau khi tạo danh mục mới cho sản phẩm thuê bao, bạn có thể di chuyển ứng dụng của mình sang Thư viện Google Billing 5. Thay thế phần phụ thuộc hiện có của Thư viện Play Billing bằng phiên bản cập nhật cho tệp build.gradle
của ứng dụng.
dependencies {
def billingVersion = "6.0.0"
implementation "com.android.billingclient:billing:$billingVersion"
}
Dự án của bạn sẽ được tạo ngay lập tức, kể cả khi bạn chưa sửa đổi bất kỳ lệnh gọi nào đối với các phương thức – Thư viện Play Billing 6 có khả năng tương thích ngược. Khái niệm SKU được coi là không dùng nữa nhưng vẫn xuất hiện để giúp quá trình chuyển đổi ứng dụng trở nên đơn giản hơn và tăng tiến nhanh hơn.
Khởi động Ứng dụng thanh toán và thiết lập kết nối với Google Play
Các bước đầu tiên để tạo giao dịch mua từ một ứng dụng Android không thay đổi:
Hiển thị các sản phẩm có sẵn để mua
Cách nhận tất cả ưu đãi người dùng đủ điều kiện để mua:
- Thay thế
SkuDetailsParams
bằngQueryProductDetailsParams
. - Chuyển lệnh gọi
BillingClient.querySkuDetailsAsync()
để sử dụngBillingClient.queryProductDetailsAsync()
Lưu ý kết quả truy vấn giờ đây sẽ là ProductDetails
thay vì SkuDetails
.
Mỗi mặt hàng ProductDetails
chứa thông tin về sản phẩm (mã nhận dạng, tiêu đề, loại, v.v.). Đối với các sản phẩm thuê bao, ProductDetails
chứa List<ProductDetails.SubscriptionOfferDetails>
, là danh sách thông tin chi tiết về ưu đãi cho thuê bao. Đối với các sản phẩm mua một lần, ProductDetails
chứa ProductDetails.OneTimePurchaseOfferDetails
. Bạn có thể dùng thông tin này để quyết định ưu đãi nào sẽ hiển thị cho người dùng.
Ví dụ sau cho thấy ứng dụng của bạn trông như thế nào trước và sau khi thực hiện những thay đổi này:
Trước
Kotlin
val skuList = ArrayList<String>() skuList.add("up_basic_sub") val params = SkuDetailsParams.newBuilder() params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS).build() billingClient.querySkuDetailsAsync(params) { billingResult, skuDetailsList -> // Process the result }
Java
List<String> skuList = new ArrayList<>(); skuList.add("up_basic_sub"); SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); params.setSkusList(skuList).setType(SkuType.SUBS).build(); billingClient.querySkuDetailsAsync(params, new SkuDetailsResponseListener() { @Override public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) { // Process the result. } } );
Sau
Kotlin
val productList = listOf( QueryProductDetailsParams.Product.newBuilder() .setProductId("up_basic_sub") .setProductType(BillingClient.ProductType.SUBS) .build() ) val params = QueryProductDetailsParams.newBuilder().setProductList(productList).build() billingClient.queryProductDetailsAsync(params) { billingResult, productDetailsList -> // Process the result }
Java
ImmutableList<Product> productList = ImmutableList.of(Product.newBuilder() .setProductId("up_basic_sub") .setProductType(ProductType.SUBS) .build()); QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder() .setProductList(productList) .build(); billingClient.queryProductDetailsAsync( params, new ProductDetailsResponseListener() { public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) { // Process the result } } );
Lệnh gọi lại cho queryProductDetailsAsync
trả về List<ProductDetails>
.
Mỗi mặt hàng ProductDetails
chứa thông tin về sản phẩm (mã nhận dạng, tiêu đề, loại, v.v.). Điểm khác biệt chính là các sản phẩm thuê bao hiện cũng chứa List<ProductDetails.SubscriptionOfferDetails>
chứa tất cả các ưu đãi người dùng có thể sử dụng.
Vì các phiên bản trước của Thư viện Play Billing không hỗ trợ các đối tượng mới (gói thuê bao, gói cơ bản, ưu đãi, v.v.), nên hệ thống mới sẽ chuyển đổi từng SKU thuê bao thành một ưu đãi và gói cơ bản có khả năng tương thích ngược. Các sản phẩm mua một lần cũng được chuyển đến đối tượng ProductDetails
. Bạn có thể truy cập thông tin chi tiết về ưu đãi của một sản phẩm mua một lần bằng phương thức getOneTimePurchaseOfferDetails()
.
Trong một số ít trường hợp, một số thiết bị không hỗ trợ ProductDetails
và queryProductDetailsAsync()
, thường là do các phiên bản Dịch vụ Google Play đã lỗi thời. Để đảm bảo nhận được sự hỗ trợ phù hợp cho trường hợp này, hãy gọi isFeatureSupported()
cho tính năng PRODUCT_DETAILS
trước khi gọi queryProductDetailsAsync
. Nếu phản hồi là OK
, thiết bị sẽ hỗ trợ tính năng này và bạn có thể tiếp tục gọi queryProductDetailsAsync()
.
Nếu phản hồi là FEATURE_NOT_SUPPORTED
, bạn có thể dùng querySkuDetailsAsync()
để yêu cầu danh sách sản phẩm có khả năng tương thích ngược.
Để tìm hiểu thêm về cách sử dụng các tính năng tương thích ngược, hãy xem hướng dẫn về các tính năng liên quan đến gói thuê bao trong tháng 5 năm 2022.
Bắt đầu quy trình mua ưu đãi
Việc bắt đầu một quy trình mua hàng cho một ưu đãi rất giống với việc ra mắt một quy trình cho SKU. Để bắt đầu một yêu cầu mua hàng bằng phiên bản 6, hãy làm như sau:
- Thay vì dùng
SkuDetails
choBillingFlowParams
, hãy dùngProductDetailsParams
. - Bạn có thể lấy thông tin chi tiết về (các) ưu đãi, chẳng hạn như mã ưu đãi, mã gói cơ bản và các thông tin khác thông qua đối tượng
SubscriptionOfferDetails
.
Để mua sản phẩm bằng ưu đãi đã chọn của người dùng, hãy lấy offerToken
của ưu đãi đã chọn và truyền ưu đãi đó vào đối tượng ProductDetailsParams
.
Sau khi bạn tạo đối tượng BillingFlowParams
, việc chạy luồng thanh toán với BillingClient
vẫn giữ nguyên.
Ví dụ sau cho thấy ứng dụng của bạn trông như thế nào trước và sau khi thực hiện những thay đổi này:
Trước
Kotlin
// An activity reference from which the billing flow will be launched. val activity : Activity = ... // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync(). val billingFlowParams = BillingFlowParams.newBuilder() .setSkuDetails(skuDetails) .build() val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
Java
// An activity reference from which the billing flow will be launched. Activity activity = ...; // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync(). BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setSkuDetails(skuDetails) .build(); BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
Sau
Kotlin
// An activity reference from which the billing flow will be launched. val activity : Activity = ...; val productDetailsParamsList = listOf( BillingFlowParams.ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // For One-time product, "setOfferToken" method shouldn't be called. // For subscriptions, to get the offer token corresponding to the selected // offer call productDetails.subscriptionOfferDetails?.get(selectedOfferIndex)?.offerToken .setOfferToken(selectedOfferToken) .build() ) val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build() // Launch the billing flow val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
Java
// An activity reference from which the billing flow will be launched. Activity activity = ...; ImmutableList<ProductDetailsParams> productDetailsParamsList = ImmutableList.of( ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // For one-time products, "setOfferToken" method shouldn't be called. // For subscriptions, to get the offer token corresponding to the selected // offer call productDetails.getSubscriptionOfferDetails().get(selectedOfferIndex).getOfferToken() .setOfferToken(selectedOfferToken) .build() ); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); // Launch the billing flow BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
Xử lý giao dịch mua
Việc xử lý các giao dịch mua bằng Thư viện Google Play Billing 6 vẫn tương tự như các phiên bản trước.
Để lấy tất cả các giao dịch mua đang hoạt động thuộc sở hữu của người dùng và truy vấn các giao dịch mua mới, hãy làm như sau:
- Thay vì chuyển giá trị
BillingClient.SkuType
đếnqueryPurchasesAsync()
, hãy chuyển đối tượngQueryPurchasesParams
chứa giá trịBillingClient.ProductType
.
Ví dụ sau cho thấy ứng dụng của bạn trông như thế nào trước và sau khi thực hiện những thay đổi này.
Trước
Kotlin
billingClient.queryPurchasesAsync(BillingClient.SkuType.SUBS) { billingResult, purchaseList -> { // Process the result } }
Java
billingClient.queryPurchasesAsync( BillingClient.SkuType.SUBS, new PurchasesResponseListener() { public void onQueryPurchasesResponse( BillingResult billingResult, ListP<urchase >purchases) { // process the result } } );
Sau
Kotlin
billingClient.queryPurchasesAsync( QueryPurchasesParams.newBuilder() .setProductType(BillingClient.ProductType.SUBS) .build() ) { billingResult, purchaseList -> // Process the result }
Java
billingClient.queryPurchasesAsync( QueryPurchasesParams.newBuilder().setProductType(ProductType.SUBS).build(), new PurchasesResponseListener() { public void onQueryPurchasesResponse( BillingResult billingResult, List<Purchase> purchases) { // Process the result } } );
Các bước để quản lý giao dịch mua ngoài ứng dụng và giao dịch đang chờ xử lý không thay đổi.
Quản lý trạng thái giao dịch mua gói thuê bao bằng API mới trong phần phụ trợ
Bạn nên di chuyển thành phần quản lý trạng thái của giao dịch mua gói thuê bao trong phần phụ trợ để sẵn sàng xử lý các giao dịch mua sản phẩm mới đã tạo ở các bước trước. Thành phần quản lý trạng thái của giao dịch mua gói thuê bao hiện tại sẽ hoạt động như bình thường đối với các sản phẩm thuê bao đã chuyển đổi mà bạn xác định trước thời điểm ra mắt tháng 5 năm 2022, và gói thuê bao cần có đủ điều kiện để quản lý các giao dịch mua ưu đãi có khả năng tương thích ngược nhưng không hỗ trợ bất kỳ chức năng mới nào.
Bạn cần triển khai Subscription Purchases API (API Giao dịch mua gói thuê bao) mới cho mô-đun quản lý trạng thái của giao dịch mua của các gói thuê bao. Mô-đun này kiểm tra trạng thái của giao dịch mua và quản lý các quyền của gói thuê bao Play Billing trong phần phụ trợ. Phiên bản cũ của API không trả về tất cả thông tin chi tiết cần thiết để quản lý các giao dịch mua trong nền tảng mới. Để biết thông tin chi tiết về những thay đổi so với các phiên bản trước, hãy xem hướng dẫn cho các tính năng mới của gói thuê bao trong tháng 5 năm 2022.
Thông thường, bạn sẽ gọi Subscription Purchases API (API Giao dịch mua gói thuê bao) mỗi khi nhận được Thông báo theo thời gian thực dành cho nhà phát triển SubscriptionNotification
để lấy thông tin mới nhất về trạng thái của gói thuê bao. Bạn cần thay thế các lệnh gọi đến purchases.subscriptions.get
bằng phiên bản mới của Subscription Purchases API (API Giao dịch mua gói thuê bao), purchases.subscriptionsv2.get
.
Có một tài nguyên mới tên là SubscriptionPurchaseV2
. Tài nguyên này cung cấp đầy đủ thông tin để quản lý quyền mua các gói thuê bao trong mô hình mới.
Điểm cuối mới này trả về trạng thái của tất cả các sản phẩm thuê bao và giao dịch mua của bạn, bất kể phiên bản ứng dụng đã bán sản phẩm và thời điểm sản phẩm được xác định (trước hoặc sau bản phát hành tháng 5 năm 2022). Vì vậy, sau khi di chuyển, bạn chỉ cần dùng phiên bản này của mô-đun quản lý trạng thái của giao dịch mua gói thuê bao.
Thay đổi giao dịch mua gói thuê bao của người dùng
Trong Thư viện Play Billing 5 trở xuống, ProrationMode
được dùng để áp dụng các thay đổi đối với giao dịch mua gói thuê bao của người dùng, chẳng hạn như nâng cấp hoặc hạ cấp. Chế độ này không còn được dùng nữa mà thay vào đó là ReplacementMode
trong phiên bản 6.
Xử lý các thay đổi về giá của gói thuê bao
API launchPriceConfirmationFlow
vốn không còn được dùng nữa, giờ đã bị xoá khỏi Thư viện Play Billing 6. Để biết các lựa chọn thay thế, hãy xem hướng dẫn về thay đổi giá.
Xử lý lỗi trong Thư viện Play Billing
Trong Thư viện Play Billing 6, một mã NETWORK_ERROR
mới đã được thêm để cho biết sự cố về kết nối mạng giữa thiết bị của người dùng và hệ thống Google Play. Mã SERVICE_TIMEOUT
và SERVICE_UNAVAILABLE
cũng có những thay đổi. Để biết thêm thông tin, hãy xem phần Xử lý mã phản hồi BillingResult.
Xử lý các giao dịch đang chờ xử lý
Kể từ phiên bản 6.0.0, Thư viện Play Billing sẽ không tạo mã đơn hàng cho các giao dịch mua đang chờ xử lý. Đối với các giao dịch mua này, mã đơn hàng sẽ được điền sau khi giao dịch mua được chuyển sang trạng thái PURCHASED
. Hãy đảm bảo rằng tiện ích tích hợp của bạn chỉ nhận mã đơn hàng sau khi giao dịch hoàn tất. Bạn vẫn có thể sử dụng mã thông báo giao dịch mua để ghi lại hồ sơ. Để biết thêm thông tin về cách xử lý các giao dịch mua đang chờ xử lý, hãy xem hướng dẫn tích hợp của Thư viện Play Billing và hướng dẫn quản lý vòng đời giao dịch mua.